All files / src/abap/5_syntax/expressions cast.ts

81.03% Statements 47/58
63.63% Branches 14/22
100% Functions 1/1
81.03% Lines 47/58

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 581x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x     7x 7x 7x 7x 7x 7x 7x   7x 2x 7x     7x 7x 5x 5x 5x 4x 4x 2x 2x 5x 1x 1x 5x   5x 1x 5x       5x 6x 6x 7x     6x 6x 6x 1x
import {ExpressionNode} from "../../nodes";
import {CurrentScope} from "../_current_scope";
import {DataReference, GenericObjectReferenceType, ObjectReferenceType, UnknownType, VoidType} from "../../types/basic";
import * as Expressions from "../../2_statements/expressions";
import {AbstractType} from "../../types/basic/_abstract_type";
import {Source} from "./source";
import {TypeUtils} from "../_type_utils";
import {BasicTypes} from "../basic_types";
 
export class Cast {
  public runSyntax(node: ExpressionNode, scope: CurrentScope, targetType: AbstractType | undefined, filename: string): AbstractType {
    const sourceNode = node.findDirectExpression(Expressions.Source);
    if (sourceNode === undefined) {
      throw new Error("Cast, source node not found");
    }
 
    const sourceType = new Source().runSyntax(sourceNode, scope, filename);
    let tt: AbstractType | undefined = undefined;
 
    const typeExpression = node.findDirectExpression(Expressions.TypeNameOrInfer);
    const typeName = typeExpression?.concatTokens();
    if (typeName === undefined) {
      throw new Error("Cast, child TypeNameOrInfer not found");
    } else if (typeName === "#" && targetType) {
      tt = targetType;
    } else if (typeName === "#") {
      throw new Error("Cast, todo, infer type");
    }
 
    if (tt === undefined && typeExpression) {
      const basic = new BasicTypes(filename, scope);
      tt = basic.parseType(typeExpression);
      if (tt === undefined || tt instanceof VoidType || tt instanceof UnknownType) {
        const found = scope.findObjectDefinition(typeName);
        if (found) {
          tt = new ObjectReferenceType(found, {qualifiedName: typeName});
        }
      } else {
        tt = new DataReference(tt, typeName);
      }
      if (tt === undefined && scope.getDDIC().inErrorNamespace(typeName) === false) {
        tt = new VoidType(typeName);
      } else if (typeName.toUpperCase() === "OBJECT") {
        return new GenericObjectReferenceType();
      } else if (tt === undefined) {
        // todo, this should be an UnknownType instead?
        throw new Error("Type \"" + typeName + "\" not found in scope, Cast");
      }
    }
    new Source().addIfInferred(node, scope, filename, tt);
 
    if (new TypeUtils(scope).isCastable(sourceType, tt) === false) {
      throw new Error("Cast, incompatible types");
    }
 
    return tt!;
  }
}