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

88.76% Statements 79/89
81.25% Branches 26/32
100% Functions 1/1
88.76% Lines 79/89

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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 891x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 82x 82x 82x 82x 17x 17x 65x 65x 82x 81x 9x 9x 72x 72x 81x 21x 81x 8x 8x       8x       8x 8x     8x 51x 43x 43x 43x 2x 2x 1x 1x 2x 42x 43x 35x 35x 2x 2x 43x 6x 6x 6x     6x 6x 6x 6x 6x 6x 2x 6x 4x 4x 4x 4x 4x 6x 7x 1x 1x 43x 81x 51x 51x 51x 1x 1x
import * as Expressions from "../../2_statements/expressions";
import {AbstractType} from "../../types/basic/_abstract_type";
import {VoidType} from "../../types/basic/void_type";
import {StructureType} from "../../types/basic/structure_type";
import {ExpressionNode} from "../../nodes";
import {DataReference, ObjectReferenceType, UnknownType} from "../../types/basic";
import {ClassDefinition} from "../../types";
import {IReferenceExtras, ReferenceType} from "../_reference";
import {CurrentScope} from "../_current_scope";
import {ObjectOriented} from "../_object_oriented";
 
export class ComponentChain {
  public runSyntax(context: AbstractType | undefined, node: ExpressionNode,
                   scope: CurrentScope,
                   filename: string): AbstractType | undefined {
 
    if (context === undefined) {
      return undefined;
    }
 
    const children = node.getChildren();
    for (let i = 0; i < children.length; i++) {
      if (context instanceof VoidType || context instanceof UnknownType) {
        return context;
      }
 
      const child = children[i];
      if (i === 0 && child.concatTokens().toUpperCase() === "TABLE_LINE") {
        continue;
      } else if (child.get() instanceof Expressions.ArrowOrDash) {
        const concat = child.concatTokens();
        if (concat === "-") {
          if (!(context instanceof StructureType)) {
            throw new Error("ComponentChain, not a structure");
          }
        } else if (concat === "=>") {
          if (!(context instanceof ObjectReferenceType)) {
            throw new Error("ComponentChain, not a reference");
          }
        } else if (concat === "->") {
          if (!(context instanceof ObjectReferenceType) && !(context instanceof DataReference)) {
            throw new Error("ComponentChain, not a reference");
          }
        }
      } else if (child.get() instanceof Expressions.ComponentName) {
        const name = child.concatTokens();
 
        if (context instanceof DataReference) {
          context = context.getType();
          if (name === "*") {
            continue;
          }
        }
 
        if (context instanceof StructureType) {
          context = context.getComponentByName(name);
          if (context === undefined) {
            throw new Error("Component \"" + name + "\" not found in structure");
          }
        } else if (context instanceof ObjectReferenceType) {
          const id = context.getIdentifier();
          const def = scope.findObjectDefinition(id.getName());
          if (def === undefined) {
            throw new Error(id.getName() + " not found in scope");
          }
 
          const helper = new ObjectOriented(scope);
          const found = helper.searchAttributeName(def, name);
 
          context = found?.getType();
          if (context === undefined) {
            throw new Error("Attribute \"" + name + "\" not found");
          } else {
            const extra: IReferenceExtras = {
              ooName: id.getName(),
              ooType: id instanceof ClassDefinition ? "CLAS" : "INTF"};
            scope.addReference(child.getFirstToken(), found, ReferenceType.DataWriteReference, filename, extra);
          }
 
        } else {
          throw new Error("ComponentChain, not a structure, " + context?.constructor.name);
        }
      }
    }
 
    return context;
  }
 
}