// buildBooleanBinaryExpression builds the CodeDOM for a boolean unary operator. func (db *domBuilder) buildBooleanBinaryExpression(node compilergraph.GraphNode, op string) codedom.Expression { boolType := db.scopegraph.TypeGraph().BoolTypeReference() leftExpr := codedom.NominalUnwrapping(db.getExpression(node, parser.NodeBinaryExpressionLeftExpr), boolType, node) rightExpr := codedom.NominalUnwrapping(db.getExpression(node, parser.NodeBinaryExpressionRightExpr), boolType, node) return codedom.NominalWrapping( codedom.BinaryOperation(leftExpr, op, rightExpr, node), db.scopegraph.TypeGraph().BoolType(), node) }
// buildIsComparisonExpression builds the CodeDOM for an is comparison operator. func (db *domBuilder) buildIsComparisonExpression(node compilergraph.GraphNode) codedom.Expression { generatedLeftExpr := db.getExpression(node, parser.NodeBinaryExpressionLeftExpr) // Check for a `not` subexpression. If found, we invert the check. op := "==" rightExpr := node.GetNode(parser.NodeBinaryExpressionRightExpr) if rightExpr.Kind() == parser.NodeKeywordNotExpression { op = "!=" rightExpr = rightExpr.GetNode(parser.NodeUnaryExpressionChildExpr) } generatedRightExpr := db.buildExpression(rightExpr) return codedom.NominalWrapping( codedom.BinaryOperation(generatedLeftExpr, op, generatedRightExpr, node), db.scopegraph.TypeGraph().BoolType(), 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 }
// buildNativeBinaryExpression builds the CodeDOM for a native unary operator. func (db *domBuilder) buildNativeBinaryExpression(node compilergraph.GraphNode, op string) codedom.Expression { leftExpr := db.getExpression(node, parser.NodeBinaryExpressionLeftExpr) rightExpr := db.getExpression(node, parser.NodeBinaryExpressionRightExpr) return codedom.BinaryOperation(leftExpr, op, rightExpr, node) }
// buildNullComparisonExpression builds the CodeDOM for a null comparison (??) operator. func (db *domBuilder) buildNullComparisonExpression(node compilergraph.GraphNode) codedom.Expression { leftExpr := db.getExpression(node, parser.NodeBinaryExpressionLeftExpr) rightExpr := db.getExpression(node, parser.NodeBinaryExpressionRightExpr) return codedom.BinaryOperation(leftExpr, "??", rightExpr, node) }