// buildMapExpression builds the CodeDOM for a map expression.
func (db *domBuilder) buildMapExpression(node compilergraph.GraphNode) codedom.Expression {
	mapScope, _ := db.scopegraph.GetScope(node)
	mapType := mapScope.ResolvedTypeRef(db.scopegraph.TypeGraph())

	eit := node.StartQuery().
		Out(parser.NodeMapExpressionChildEntry).
		BuildNodeIterator()

	var keyExprs = make([]codedom.Expression, 0)
	var valueExprs = make([]codedom.Expression, 0)

	for eit.Next() {
		entryNode := eit.Node()

		keyExprs = append(keyExprs, db.getExpression(entryNode, parser.NodeMapExpressionEntryKey))
		valueExprs = append(valueExprs, db.getExpression(entryNode, parser.NodeMapExpressionEntryValue))
	}

	if len(valueExprs) == 0 {
		// Empty map. Call the new() constructor directly.
		constructor, _ := mapType.ResolveMember("new", typegraph.MemberResolutionStatic)
		return codedom.MemberCall(
			codedom.MemberReference(codedom.TypeLiteral(mapType, node), constructor, node),
			constructor,
			[]codedom.Expression{},
			node)
	}

	constructor, _ := mapType.ResolveMember("forArrays", typegraph.MemberResolutionStatic)
	return codedom.MemberCall(
		codedom.MemberReference(codedom.TypeLiteral(mapType, node), constructor, node),
		constructor,
		[]codedom.Expression{codedom.ArrayLiteral(keyExprs, node), codedom.ArrayLiteral(valueExprs, node)},
		node)
}
// buildTemplateStringCall builds the CodeDOM representing the call to a template string function.
func (db *domBuilder) buildTemplateStringCall(node compilergraph.GraphNode, funcExpr codedom.Expression, isTagged bool) codedom.Expression {
	pit := node.StartQuery().
		Out(parser.NodeTemplateStringPiece).
		BuildNodeIterator()

	var pieceExprs = make([]codedom.Expression, 0)
	var valueExprs = make([]codedom.Expression, 0)

	var isPiece = true
	for pit.Next() {
		if isPiece {
			pieceExprs = append(pieceExprs, db.buildExpression(pit.Node()))
		} else {
			valueExprs = append(valueExprs, db.buildExpression(pit.Node()))
		}

		isPiece = !isPiece
	}

	// Handle common case: No literal string piece at all.
	if len(pieceExprs) == 0 {
		return codedom.NominalWrapping(codedom.LiteralValue("''", node), db.scopegraph.TypeGraph().StringType(), node)
	}

	// Handle common case: A single literal string piece with no values.
	if len(pieceExprs) == 1 && len(valueExprs) == 0 {
		return pieceExprs[0]
	}

	pieceSliceType := db.scopegraph.TypeGraph().SliceTypeReference(db.scopegraph.TypeGraph().StringTypeReference())
	valueSliceType := db.scopegraph.TypeGraph().SliceTypeReference(db.scopegraph.TypeGraph().StringableTypeReference())

	constructor, _ := pieceSliceType.ResolveMember("overArray", typegraph.MemberResolutionStatic)

	pieceSliceExpr := codedom.MemberCall(
		codedom.MemberReference(
			codedom.TypeLiteral(pieceSliceType, node), constructor, node),
		constructor,
		[]codedom.Expression{codedom.ArrayLiteral(pieceExprs, node)},
		node)

	valueSliceExpr := codedom.MemberCall(
		codedom.MemberReference(
			codedom.TypeLiteral(valueSliceType, node), constructor, node),
		constructor,
		[]codedom.Expression{codedom.ArrayLiteral(valueExprs, node)},
		node)

	return codedom.AwaitPromise(codedom.FunctionCall(funcExpr, []codedom.Expression{pieceSliceExpr, valueSliceExpr}, node), node)
}
// buildCollectionInitializerExpression builds a literal collection expression.
func (db *domBuilder) buildCollectionInitializerExpression(collectionType typegraph.TypeReference, valueExprs []codedom.Expression, emptyConstructorName string, arrayConstructorName string, node compilergraph.GraphNode) codedom.Expression {
	if len(valueExprs) == 0 {
		// Empty collection. Call the empty constructor directly.
		constructor, _ := collectionType.ResolveMember(emptyConstructorName, typegraph.MemberResolutionStatic)
		return codedom.MemberCall(
			codedom.MemberReference(codedom.TypeLiteral(collectionType, node), constructor, node),
			constructor,
			[]codedom.Expression{},
			node)
	}

	arrayExpr := codedom.ArrayLiteral(valueExprs, node)

	constructor, _ := collectionType.ResolveMember(arrayConstructorName, typegraph.MemberResolutionStatic)
	return codedom.MemberCall(
		codedom.MemberReference(codedom.TypeLiteral(collectionType, node), constructor, node),
		constructor,
		[]codedom.Expression{arrayExpr},
		node)
}
Beispiel #4
0
// generateMemberCall generates the expression source for a call to a module or type member.
func (eg *expressionGenerator) generateMemberCall(memberCall *codedom.MemberCallNode, context generationContext) esbuilder.ExpressionBuilder {
	if memberCall.Member.IsOperator() && memberCall.Member.IsNative() {
		// This is a call to a native operator.
		if memberCall.Member.Name() != "index" {
			panic("Native call to non-index operator")
		}

		refExpr := memberCall.ChildExpression.(*codedom.MemberReferenceNode).ChildExpression
		return eg.generateExpression(codedom.NativeIndexing(refExpr, memberCall.Arguments[0], memberCall.BasisNode()), context)
	}

	callPath := memberCall.ChildExpression
	arguments := memberCall.Arguments

	var functionCall = codedom.FunctionCall(callPath, arguments, memberCall.BasisNode())
	if memberCall.Nullable {
		// Invoke the function with a specialized nullable-invoke.
		refExpr := callPath.(*codedom.DynamicAccessNode).ChildExpression

		var isPromising = "false"
		if memberCall.Member.IsPromising() {
			isPromising = "true"
		}

		localArguments := []codedom.Expression{
			refExpr,
			codedom.LiteralValue("'"+memberCall.Member.Name()+"'", refExpr.BasisNode()),
			codedom.LiteralValue(isPromising, memberCall.BasisNode()),
			codedom.ArrayLiteral(arguments, memberCall.BasisNode()),
		}

		functionCall = codedom.RuntimeFunctionCall(codedom.NullableInvokeFunction, localArguments, memberCall.BasisNode())
	}

	return eg.generateExpression(codedom.WrapIfPromising(functionCall, memberCall.Member, memberCall.BasisNode()), context)
}