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

81.66% Statements 49/60
63.63% Branches 14/22
100% Functions 1/1
81.66% Lines 49/60

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 58 59 601x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 11x 11x     11x 11x 11x 11x 11x 11x 11x   11x 2x 11x     11x 11x 9x 9x 9x 7x 7x 4x 4x 4x 9x 2x 2x 9x   9x 1x 9x       9x 10x 10x 11x     10x 10x 10x 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";
import {ReferenceType} from "../_reference";
 
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});
          scope.addReference(typeExpression.getFirstToken(), found, ReferenceType.ObjectOrientedReference, filename);
        }
      } 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!;
  }
}