// buildFunctionCall builds the CodeDOM for a function call. func (db *domBuilder) buildFunctionCall(node compilergraph.GraphNode) codedom.Expression { childExprNode := node.GetNode(parser.NodeFunctionCallExpressionChildExpr) childScope, _ := db.scopegraph.GetScope(childExprNode) // Check if the child expression has a static scope. If so, this is a type conversion between // a nominal type and a base type. if childScope.GetKind() == proto.ScopeKind_STATIC { wrappedExprNode := node.GetNode(parser.NodeFunctionCallArgument) wrappedExprScope, _ := db.scopegraph.GetScope(wrappedExprNode) wrappedExprType := wrappedExprScope.ResolvedTypeRef(db.scopegraph.TypeGraph()) wrappedExpr := db.buildExpression(wrappedExprNode) targetTypeRef := childScope.StaticTypeRef(db.scopegraph.TypeGraph()) // If the targetTypeRef is not nominal or structural, then we know we are unwrapping. if !targetTypeRef.IsNominalOrStruct() { return codedom.NominalUnwrapping(wrappedExpr, wrappedExprType, node) } else { return codedom.NominalRefWrapping(wrappedExpr, wrappedExprType, targetTypeRef, node) } } // Collect the expressions for the arguments. ait := node.StartQuery(). Out(parser.NodeFunctionCallArgument). BuildNodeIterator() arguments := db.buildExpressions(ait, buildExprCheckNominalShortcutting) childExpr := db.buildExpression(childExprNode) // If the function call is to a member, then we return a MemberCall. namedRef, isNamed := db.scopegraph.GetReferencedName(childScope) if isNamed && !namedRef.IsLocal() { member, _ := namedRef.Member() if childExprNode.Kind() == parser.NodeNullableMemberAccessExpression { return codedom.NullableMemberCall(childExpr, member, arguments, node) } return codedom.MemberCall(childExpr, member, arguments, node) } // Otherwise, this is a normal function call with an await. return codedom.AwaitPromise(codedom.FunctionCall(childExpr, arguments, node), node) }
// buildExpression builds the CodeDOM for the given SRG node and returns it as an expression. Will // panic if the returned DOM type is not an expression. func (db *domBuilder) buildExpression(node compilergraph.GraphNode) codedom.Expression { switch node.Kind() { // Access Expressions. case parser.NodeMemberAccessExpression: fallthrough case parser.NodeNullableMemberAccessExpression: fallthrough case parser.NodeDynamicMemberAccessExpression: return db.buildMemberAccessExpression(node) case parser.NodeTypeIdentifierExpression: return db.buildIdentifierExpression(node) case parser.NodeGenericSpecifierExpression: return db.buildGenericSpecifierExpression(node) case parser.NodeCastExpression: return db.buildCastExpression(node) case parser.NodeStreamMemberAccessExpression: return db.buildStreamMemberAccessExpression(node) // Await Expression. case parser.NodeTypeAwaitExpression: return db.buildAwaitExpression(node) // Lambda Expressions. case parser.NodeTypeLambdaExpression: return db.buildLambdaExpression(node) // SML Expressions. case parser.NodeTypeSmlExpression: return db.buildSmlExpression(node) case parser.NodeTypeSmlText: return db.buildSmlText(node) // Flow Expressions. case parser.NodeTypeConditionalExpression: return db.buildConditionalExpression(node) case parser.NodeTypeLoopExpression: return db.buildLoopExpression(node) // Op Expressions. case parser.NodeRootTypeExpression: return db.buildRootTypeExpression(node) case parser.NodeFunctionCallExpression: return db.buildFunctionCall(node) case parser.NodeSliceExpression: return db.buildSliceExpression(node) case parser.NodeNullComparisonExpression: return db.buildNullComparisonExpression(node) case parser.NodeAssertNotNullExpression: return db.buildAssertNotNullExpression(node) case parser.NodeIsComparisonExpression: return db.buildIsComparisonExpression(node) case parser.NodeInCollectionExpression: return db.buildInCollectionExpression(node) case parser.NodeBitwiseNotExpression: return db.buildUnaryOperatorExpression(node, nil) case parser.NodeKeywordNotExpression: return db.buildUnaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression { boolType := db.scopegraph.TypeGraph().BoolTypeReference() childExpr := codedom.UnaryOperation("!", codedom.NominalUnwrapping(expr, boolType, node), node) return codedom.NominalWrapping( childExpr, db.scopegraph.TypeGraph().BoolType(), node) }) case parser.NodeDefineRangeExpression: fallthrough case parser.NodeBitwiseXorExpression: fallthrough case parser.NodeBitwiseOrExpression: fallthrough case parser.NodeBitwiseAndExpression: fallthrough case parser.NodeBitwiseShiftLeftExpression: fallthrough case parser.NodeBitwiseShiftRightExpression: fallthrough case parser.NodeBinaryAddExpression: fallthrough case parser.NodeBinarySubtractExpression: fallthrough case parser.NodeBinaryMultiplyExpression: fallthrough case parser.NodeBinaryDivideExpression: fallthrough case parser.NodeBinaryModuloExpression: return db.buildBinaryOperatorExpression(node, nil) case parser.NodeComparisonEqualsExpression: return db.buildBinaryOperatorExpression(node, nil) case parser.NodeComparisonNotEqualsExpression: return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression { boolType := db.scopegraph.TypeGraph().BoolTypeReference() childExpr := codedom.UnaryOperation("!", codedom.NominalUnwrapping(expr, boolType, node), node) return codedom.NominalRefWrapping( childExpr, boolType.NominalDataType(), boolType, node) }) case parser.NodeComparisonLTEExpression: return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression { intType := db.scopegraph.TypeGraph().IntTypeReference() boolType := db.scopegraph.TypeGraph().BoolTypeReference() childExpr := codedom.BinaryOperation(codedom.NominalUnwrapping(expr, intType, node), "<=", codedom.LiteralValue("0", node), node) return codedom.NominalRefWrapping( childExpr, boolType.NominalDataType(), boolType, node) }) case parser.NodeComparisonLTExpression: return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression { intType := db.scopegraph.TypeGraph().IntTypeReference() boolType := db.scopegraph.TypeGraph().BoolTypeReference() childExpr := codedom.BinaryOperation(codedom.NominalUnwrapping(expr, intType, node), "<", codedom.LiteralValue("0", node), node) return codedom.NominalRefWrapping( childExpr, boolType.NominalDataType(), boolType, node) }) case parser.NodeComparisonGTEExpression: return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression { intType := db.scopegraph.TypeGraph().IntTypeReference() boolType := db.scopegraph.TypeGraph().BoolTypeReference() childExpr := codedom.BinaryOperation(codedom.NominalUnwrapping(expr, intType, node), ">=", codedom.LiteralValue("0", node), node) return codedom.NominalRefWrapping( childExpr, boolType.NominalDataType(), boolType, node) }) case parser.NodeComparisonGTExpression: return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression { intType := db.scopegraph.TypeGraph().IntTypeReference() boolType := db.scopegraph.TypeGraph().BoolTypeReference() childExpr := codedom.BinaryOperation(codedom.NominalUnwrapping(expr, intType, node), ">", codedom.LiteralValue("0", node), node) return codedom.NominalRefWrapping( childExpr, boolType.NominalDataType(), boolType, node) }) // Boolean operators. case parser.NodeBooleanAndExpression: return db.buildBooleanBinaryExpression(node, "&&") case parser.NodeBooleanOrExpression: return db.buildBooleanBinaryExpression(node, "||") case parser.NodeBooleanNotExpression: return db.buildBooleanUnaryExpression(node, "!") // Literals. case parser.NodeStructuralNewExpression: return db.buildStructuralNewExpression(node) case parser.NodeNumericLiteralExpression: return db.buildNumericLiteral(node) case parser.NodeBooleanLiteralExpression: return db.buildBooleanLiteral(node) case parser.NodeStringLiteralExpression: return db.buildStringLiteral(node) case parser.NodeNullLiteralExpression: return db.buildNullLiteral(node) case parser.NodeThisLiteralExpression: return db.buildThisLiteral(node) case parser.NodeValLiteralExpression: return db.buildValLiteral(node) case parser.NodeListExpression: return db.buildListExpression(node) case parser.NodeSliceLiteralExpression: return db.buildSliceLiteralExpression(node) case parser.NodeMappingLiteralExpression: return db.buildMappingLiteralExpression(node) case parser.NodeMapExpression: return db.buildMapExpression(node) case parser.NodeTypeTemplateString: return db.buildTemplateStringExpression(node) case parser.NodeTaggedTemplateLiteralString: return db.buildTaggedTemplateString(node) default: panic(fmt.Sprintf("Unknown SRG expression node: %s", node.Kind())) return nil } }
func (db *domBuilder) buildOptimizedBinaryOperatorExpression(node compilergraph.GraphNode, parentType typegraph.TypeReference, leftExpr codedom.Expression, rightExpr codedom.Expression) (codedom.Expression, bool) { // Verify this is a supported native operator. opString, hasOp := operatorMap[node.Kind()] if !hasOp { return nil, false } // Verify we have a native binary operator we can optimize. if !parentType.IsNominal() { return nil, false } isNumeric := false switch { case parentType.IsDirectReferenceTo(db.scopegraph.TypeGraph().IntType()): isNumeric = true case parentType.IsDirectReferenceTo(db.scopegraph.TypeGraph().BoolType()): fallthrough case parentType.IsDirectReferenceTo(db.scopegraph.TypeGraph().StringType()): fallthrough default: return nil, false } // Handle the various kinds of operators. switch node.Kind() { case parser.NodeComparisonEqualsExpression: fallthrough case parser.NodeComparisonNotEqualsExpression: // Always allowed. break case parser.NodeComparisonLTEExpression: fallthrough case parser.NodeComparisonLTExpression: fallthrough case parser.NodeComparisonGTEExpression: fallthrough case parser.NodeComparisonGTExpression: // Only allowed for number. if !isNumeric { return nil, false } } boolType := db.scopegraph.TypeGraph().BoolTypeReference() unwrappedLeftExpr := codedom.NominalUnwrapping(leftExpr, parentType, node) unwrappedRightExpr := codedom.NominalUnwrapping(rightExpr, parentType, node) compareExpr := codedom.BinaryOperation(unwrappedLeftExpr, opString, unwrappedRightExpr, node) return codedom.NominalRefWrapping(compareExpr, boolType.NominalDataType(), boolType, node), true }