// buildBinaryOperatorExpression builds the CodeDOM for a binary operator. func (db *domBuilder) buildBinaryOperatorExpression(node compilergraph.GraphNode, modifier exprModifier) codedom.Expression { scope, _ := db.scopegraph.GetScope(node) operator, _ := scope.CalledOperator(db.scopegraph.TypeGraph()) if operator.IsNative() { return db.buildNativeBinaryExpression(node, operatorMap[node.Kind()]) } leftExpr := db.getExpression(node, parser.NodeBinaryExpressionLeftExpr) rightExpr := db.getExpression(node, parser.NodeBinaryExpressionRightExpr) leftScope, _ := db.scopegraph.GetScope(node.GetNode(parser.NodeBinaryExpressionLeftExpr)) parentType := leftScope.ResolvedTypeRef(db.scopegraph.TypeGraph()) optimized, wasOptimized := db.buildOptimizedBinaryOperatorExpression(node, parentType, leftExpr, rightExpr) if wasOptimized { return optimized } callExpr := codedom.MemberCall(codedom.StaticMemberReference(operator, parentType, node), operator, []codedom.Expression{leftExpr, rightExpr}, node) if modifier != nil { return modifier(callExpr) } return callExpr }
// buildTemplateStringExpression builds the CodeDOM for a template string expression. func (db *domBuilder) buildTemplateStringExpression(node compilergraph.GraphNode) codedom.Expression { member, found := db.scopegraph.TypeGraph().StringType().ParentModule().FindMember("formatTemplateString") if !found { panic("Missing formatTemplateString under String's module") } return db.buildTemplateStringCall(node, codedom.StaticMemberReference(member, db.scopegraph.TypeGraph().StringTypeReference(), node), false) }
// buildLoopExpression builds the CodeDOM for a loop expression. func (db *domBuilder) buildLoopExpression(node compilergraph.GraphNode) codedom.Expression { member, found := db.scopegraph.TypeGraph().StreamType().ParentModule().FindMember("MapStream") if !found { panic("Missing MapStream function under Stream's module") } // Retrieve the item type for the members of the stream and the mapped values. mapExpr := node.GetNode(parser.NodeLoopExpressionMapExpression) namedValue := node.GetNode(parser.NodeLoopExpressionNamedValue) namedScope, _ := db.scopegraph.GetScope(namedValue) namedItemType := namedScope.AssignableTypeRef(db.scopegraph.TypeGraph()) mapScope, _ := db.scopegraph.GetScope(mapExpr) mappedItemType := mapScope.ResolvedTypeRef(db.scopegraph.TypeGraph()) // Build a reference to the Map function. mapFunctionReference := codedom.FunctionCall( codedom.StaticMemberReference(member, db.scopegraph.TypeGraph().StreamTypeReference(mappedItemType), node), []codedom.Expression{ codedom.TypeLiteral(namedItemType, node), codedom.TypeLiteral(mappedItemType, node), }, node) // A loop expression is replaced with a call to the Map function, with the stream as the first parameter // and a mapper function which resolves the mapped value as the second. builtMapExpr := db.buildExpression(mapExpr) builtStreamExpr := db.getExpression(node, parser.NodeLoopExpressionStreamExpression) loopValueName := namedValue.Get(parser.NodeNamedValueName) mapperFunction := codedom.FunctionDefinition( []string{}, []string{loopValueName}, codedom.Resolution(builtMapExpr, builtMapExpr.BasisNode()), false, codedom.NormalFunction, builtMapExpr.BasisNode()) return codedom.AwaitPromise( codedom.FunctionCall(mapFunctionReference, []codedom.Expression{builtStreamExpr, mapperFunction}, node), node) }
// buildUnaryOperatorExpression builds the CodeDOM for a unary operator. func (db *domBuilder) buildUnaryOperatorExpression(node compilergraph.GraphNode, modifier exprModifier) codedom.Expression { scope, _ := db.scopegraph.GetScope(node) operator, _ := scope.CalledOperator(db.scopegraph.TypeGraph()) if operator.IsNative() { return db.buildNativeUnaryExpression(node, operatorMap[node.Kind()]) } childScope, _ := db.scopegraph.GetScope(node.GetNode(parser.NodeUnaryExpressionChildExpr)) parentType := childScope.ResolvedTypeRef(db.scopegraph.TypeGraph()) childExpr := db.getExpression(node, parser.NodeUnaryExpressionChildExpr) callExpr := codedom.MemberCall(codedom.StaticMemberReference(operator, parentType, node), operator, []codedom.Expression{childExpr}, node) if modifier != nil { return modifier(callExpr) } return callExpr }
// buildNamedAccess builds the CodeDOM for a member access expression. func (db *domBuilder) buildNamedAccess(node compilergraph.GraphNode, name string, childExprNode *compilergraph.GraphNode) codedom.Expression { scope, _ := db.scopegraph.GetScope(node) namedReference, hasNamedReference := db.scopegraph.GetReferencedName(scope) // Reference to an unknown name or a nullable member access must be a dynamic access. if !hasNamedReference || node.Kind() == parser.NodeNullableMemberAccessExpression { return codedom.DynamicAccess(db.buildExpression(*childExprNode), name, node) } // Reference to a local name is a var or parameter. if namedReference.IsLocal() { return codedom.LocalReference(namedReference.Name(), node) } // Check for a reference to a type. if typeRef, isType := namedReference.Type(); isType { return codedom.StaticTypeReference(typeRef, node) } // Check for a reference to a member. if memberRef, isMember := namedReference.Member(); isMember { // If the member is under a child expression, build as an access expression. if childExprNode != nil { childExpr := db.buildExpression(*childExprNode) _, underFuncCall := node.TryGetIncomingNode(parser.NodeFunctionCallExpressionChildExpr) isAliasedFunctionReference := scope.ResolvedTypeRef(db.scopegraph.TypeGraph()).HasReferredType(db.scopegraph.TypeGraph().FunctionType()) if isAliasedFunctionReference && !underFuncCall { return codedom.DynamicAccess(childExpr, memberRef.Name(), node) } else { return codedom.MemberReference(childExpr, memberRef, node) } } else { // This is a direct access of a static member. Generate an access under the module. return codedom.StaticMemberReference(memberRef, db.scopegraph.TypeGraph().AnyTypeReference(), node) } } panic("Unknown kind of named access") return nil }
// generateMemberReference generates the expression for a reference to a module or type member. func (eg *expressionGenerator) generateMemberReference(memberReference *codedom.MemberReferenceNode, context generationContext) esbuilder.ExpressionBuilder { // If the target member is implicitly called, then this is a property that needs to be accessed via a call. if memberReference.Member.IsImplicitlyCalled() { basisNode := memberReference.BasisNode() memberCall := codedom.MemberCall( codedom.NativeAccess(memberReference.ChildExpression, memberReference.Member.Name(), basisNode), memberReference.Member, []codedom.Expression{}, basisNode) return eg.generateExpression(memberCall, context) } // This handles the native new case for WebIDL. We should probably handle this directly. if memberReference.Member.IsStatic() && !memberReference.Member.IsPromising() { return eg.generateExpression(codedom.StaticMemberReference(memberReference.Member, eg.scopegraph.TypeGraph().AnyTypeReference(), memberReference.BasisNode()), context) } childExpr := eg.generateExpression(memberReference.ChildExpression, context) return childExpr.Member(eg.pather.GetMemberName(memberReference.Member)) }