Example #1
0
// 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)
}
Example #2
0
// 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
	}
}
Example #3
0
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
}