// buildInitializationCompoundExpression builds the compound expression for calling the specified initializers on a struct. func (db *domBuilder) buildInitializationCompoundExpression(structType typegraph.TypeReference, initializers map[string]codedom.Expression, structValue codedom.Expression, node compilergraph.GraphNode) codedom.Expression { // Create a variable to hold the struct instance. structInstanceVarName := db.generateScopeVarName(node) // Build the assignment expressions. assignmentExpressions := make([]codedom.Expression, len(initializers)) var index = 0 for fieldName, initializer := range initializers { member, found := structType.ResolveMember(fieldName, typegraph.MemberResolutionInstance) if !found { panic("Member not found in struct initializer construction") } assignmentExpressions[index] = codedom.MemberAssignment(member, codedom.MemberReference( codedom.LocalReference(structInstanceVarName, node), member, node), initializer, node) index = index + 1 } // Return a compound expression that takes in the struct value and the assignment expressions, // executes them, and returns the struct value. return codedom.CompoundExpression(structInstanceVarName, structValue, assignmentExpressions, codedom.LocalReference(structInstanceVarName, node), node) }
// buildMappingInitializerExpression builds the CodeDOM for initializing a mapping literal expression. func (db *domBuilder) buildMappingInitializerExpression(mappingType typegraph.TypeReference, initializers map[string]codedom.Expression, node compilergraph.GraphNode) codedom.Expression { var entries = make([]codedom.ObjectLiteralEntryNode, 0) for name, expr := range initializers { entries = append(entries, codedom.ObjectLiteralEntryNode{ codedom.LiteralValue(strconv.Quote(name), expr.BasisNode()), expr, expr.BasisNode(), }) } if len(entries) == 0 { // Empty mapping. Call the Empty() constructor directly. constructor, _ := mappingType.ResolveMember("Empty", typegraph.MemberResolutionStatic) return codedom.MemberCall( codedom.MemberReference(codedom.TypeLiteral(mappingType, node), constructor, node), constructor, []codedom.Expression{}, node) } constructor, _ := mappingType.ResolveMember("overObject", typegraph.MemberResolutionStatic) return codedom.MemberCall( codedom.MemberReference(codedom.TypeLiteral(mappingType, node), constructor, node), constructor, []codedom.Expression{codedom.ObjectLiteral(entries, node)}, node) }
// buildStructInitializerExpression builds an initializer expression for a struct type. func (db *domBuilder) buildStructInitializerExpression(structType typegraph.TypeReference, initializers map[string]codedom.Expression, node compilergraph.GraphNode) codedom.Expression { staticType := structType.ReferredType() var arguments = make([]codedom.Expression, 0) for _, field := range staticType.RequiredFields() { arguments = append(arguments, initializers[field.Name()]) delete(initializers, field.Name()) } constructor, found := structType.ResolveMember("new", typegraph.MemberResolutionStatic) if !found { panic(fmt.Sprintf("Missing new constructor on type %v", structType)) } newCall := codedom.MemberCall( codedom.MemberReference( codedom.TypeLiteral(structType, node), constructor, node), constructor, arguments, node) // If there are no initializers, then just return the new value directly. if len(initializers) == 0 { return newCall } return db.buildInitializationCompoundExpression(structType, initializers, newCall, node) }
// AreEqual returns a call to the comparison operator between the two expressions. func AreEqual(leftExpr Expression, rightExpr Expression, comparisonType typegraph.TypeReference, tdg *typegraph.TypeGraph, basis compilergraph.GraphNode) Expression { operator, found := comparisonType.ResolveMember("equals", typegraph.MemberResolutionOperator) if !found { panic(fmt.Sprintf("Unknown equals operator under type %v", comparisonType)) } return MemberCall( StaticMemberReference(operator, comparisonType, basis), operator, []Expression{leftExpr, rightExpr}, basis) }
// 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) }
// buildStructCloneExpression builds a clone expression for a struct type. func (db *domBuilder) buildStructCloneExpression(structType typegraph.TypeReference, initializers map[string]codedom.Expression, node compilergraph.GraphNode) codedom.Expression { cloneMethod, found := structType.ResolveMember("Clone", typegraph.MemberResolutionInstance) if !found { panic(fmt.Sprintf("Missing Clone() method on type %v", structType)) } cloneCall := codedom.MemberCall( codedom.MemberReference( db.getExpression(node, parser.NodeStructuralNewTypeExpression), cloneMethod, node), cloneMethod, []codedom.Expression{}, node) // If there are no initializers, then just return the cloned value directly. if len(initializers) == 0 { return cloneCall } return db.buildInitializationCompoundExpression(structType, initializers, cloneCall, node) }