(expr: Expression, target: Type, source?: Type)
| 71 | * Convert the expression of source type to target type if necessary. |
| 72 | */ |
| 73 | export function castExpression(expr: Expression, target: Type, source?: Type): Expression { |
| 74 | if (target.category == 'any') |
| 75 | return expr; |
| 76 | // The operands of ?: do not necessarily have same type. |
| 77 | if (expr instanceof ConditionalExpression) { |
| 78 | expr.whenTrue = strictCastExpression(expr.whenTrue, target); |
| 79 | expr.whenFalse = strictCastExpression(expr.whenFalse, target); |
| 80 | return expr; |
| 81 | } |
| 82 | // The array literal's type depends on the target type. |
| 83 | if (expr instanceof ArrayLiteralExpression && target.category == 'array') { |
| 84 | // Change array type to target type if: |
| 85 | // 1. This is an empty array, i.e. []. |
| 86 | // 2. The element type is directly assignable to target type. |
| 87 | if (expr.elements.length == 0 || |
| 88 | target.getElementType().assignableWith(expr.type.getElementType())) { |
| 89 | expr.type.types[0] = target.getElementType().clone(); |
| 90 | expr.elements = expr.elements.map(e => castExpression(e, expr.type.getElementType())); |
| 91 | return expr; |
| 92 | } |
| 93 | } |
| 94 | // The numeric literal's type is dynamic, it could be the target type if it |
| 95 | // is a direct assignment, otherwise it requires a explicit conversion. |
| 96 | if (expr instanceof NumericLiteral) { |
| 97 | if (target.category == 'primitive') |
| 98 | return expr; |
| 99 | return new CustomExpression(target, (ctx) => { |
| 100 | return `static_cast<double>(${expr.print(ctx)})`; |
| 101 | }); |
| 102 | } |
| 103 | source = source ?? expr.type; |
| 104 | // Parse composited types. |
| 105 | if (source.category == 'union' || target.category == 'union') { |
| 106 | expr = castUnion(expr, target, source); |
| 107 | source = expr.type; |
| 108 | } else if (source.isOptional || target.isOptional) { |
| 109 | expr = castOptional(expr, target, source); |
| 110 | source = expr.type; |
| 111 | } |
| 112 | // We don't support using methods as functors yet. |
| 113 | if (source.category == 'method' && target.category == 'functor') |
| 114 | throw new Error('Can not use method as function'); |
| 115 | // Convert function pointer to functor object. |
| 116 | if (source.category == 'function' && target.category == 'functor') { |
| 117 | return new CustomExpression(target, (ctx) => { |
| 118 | ctx.features.add('function'); |
| 119 | const signature = (target as FunctionType).getSignature(); |
| 120 | return `compilets::MakeFunction<${signature}>(${expr.print(ctx)})`; |
| 121 | }); |
| 122 | } |
| 123 | // Convert between primitive types. |
| 124 | if (source.category == 'primitive' && target.category == 'primitive') { |
| 125 | if (source.name == target.name) |
| 126 | return expr; |
| 127 | return new CustomExpression(target, (ctx) => { |
| 128 | return `static_cast<${target.name}>(${expr.print(ctx)})`; |
| 129 | }); |
| 130 | } |
no test coverage detected