All files / src/abap/5_syntax/statements loop.ts

91.12% Statements 113/124
91.8% Branches 56/61
100% Functions 1/1
91.12% Lines 113/124

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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 1241x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 125x 125x 125x 125x 125x 47x 47x 125x 125x 125x 125x 125x 125x 3x 3x 125x 125x 125x 125x 125x 1x 1x       1x 125x       124x 124x 124x 124x 1x 1x 1x 124x 123x 123x 123x 123x       123x 123x 123x 1x 1x 1x 1x 122x 125x 125x 100x 100x 100x 18x 18x 100x 122x 122x 125x 125x 1x 1x 1x 1x 121x 125x 125x 57x 57x 121x 125x 6x 2x 2x 4x 4x 121x 125x 125x 1x 125x 120x 120x 36x 36x 120x 121x 125x 10x 10x 121x 125x     121x 121x 125x 20x 20x 125x 125x 1x
import * as Expressions from "../../2_statements/expressions";
import {StatementNode} from "../../nodes";
import {VoidType, TableType, UnknownType, DataReference, AnyType, DataType} from "../../types/basic";
import {Target} from "../expressions/target";
import {Source} from "../expressions/source";
import {InlineData} from "../expressions/inline_data";
import {InlineFS} from "../expressions/inline_fs";
import {FSTarget} from "../expressions/fstarget";
import {ComponentCond} from "../expressions/component_cond";
import {Dynamic} from "../expressions/dynamic";
import {StatementSyntax} from "../_statement_syntax";
import {LoopGroupBy} from "../expressions/loop_group_by";
import {AbstractType} from "../../types/basic/_abstract_type";
import {SyntaxInput, syntaxIssue} from "../_syntax_input";
 
export class Loop implements StatementSyntax {
  public runSyntax(node: StatementNode, input: SyntaxInput): void {
    const loopTarget = node.findDirectExpression(Expressions.LoopTarget);
 
    let target = loopTarget?.findDirectExpression(Expressions.Target);
    const targetType = target ? new Target().runSyntax(target, input) : undefined;
    if (target === undefined) {
      target = node.findDirectExpression(Expressions.FSTarget);
    }
 
    const write = loopTarget?.findDirectTokenByText("ASSIGNING") !== undefined;
 
    const sources = node.findDirectExpressions(Expressions.Source);
    let firstSource = node.findDirectExpression(Expressions.SimpleSource2);
    if (firstSource === undefined) {
      firstSource = sources[0];
    }
    let sourceType = firstSource ? new Source().runSyntax(firstSource, input, targetType, write) : undefined;
    let rowType: AbstractType | undefined = undefined;
 
    const concat = node.concatTokens().toUpperCase();
    if (sourceType === undefined) {
      // if its a dynpro table control loop, then dont issue error
      if (concat !== "LOOP.") {
        const message = "No source type determined";
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      }
      return;
    } else if (sourceType instanceof UnknownType) {
      const message = "Loop, not a table type, " + sourceType.getError();
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    } else if (sourceType instanceof TableType
        && target === undefined
        && sourceType.isWithHeader() === false
        && node.getChildren().length === 4) {
      const message = "Loop, no header line";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    } else if (!(sourceType instanceof TableType)
        && !(sourceType instanceof AnyType)
        && !(sourceType instanceof DataType)
        && !(sourceType instanceof VoidType)
        && concat.startsWith("LOOP AT GROUP ") === false) {
      const message = "Loop, not a table type";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    } else if (loopTarget === undefined
        && sourceType instanceof TableType
        && sourceType.isWithHeader() === false) {
      const message = "Loop, no header";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    const targetConcat = loopTarget?.concatTokens().toUpperCase();
    if (sourceType instanceof TableType) {
      rowType = sourceType.getRowType();
      sourceType = rowType;
      if (targetConcat?.startsWith("REFERENCE INTO ")) {
        sourceType = new DataReference(sourceType);
      }
    }
 
    if (targetConcat
        && targetConcat.startsWith("TRANSPORTING ")
        && node.findDirectTokenByText("WHERE") === undefined) {
      const message = "Loop, TRANSPORTING NO FIELDS only with WHERE";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    const inline = target?.findDirectExpression(Expressions.InlineData);
    if (inline) {
      new InlineData().runSyntax(inline, input, sourceType);
    }
 
    for (const s of sources) {
      if (s === firstSource) {
        continue;
      }
      new Source().runSyntax(s, input);
    }
 
    const inlinefs = target?.findDirectExpression(Expressions.InlineFS);
    if (inlinefs) {
      new InlineFS().runSyntax(inlinefs, input, sourceType);
    } else {
      const fstarget = loopTarget?.findDirectExpression(Expressions.FSTarget);
      if (fstarget) {
        new FSTarget().runSyntax(fstarget, input, sourceType);
      }
    }
 
    for (const t of node.findDirectExpressions(Expressions.ComponentCond)) {
      new ComponentCond().runSyntax(t, input, rowType);
    }
 
    for (const t of node.findDirectExpressions(Expressions.Dynamic)) {
      new Dynamic().runSyntax(t, input);
    }
 
    const group = node.findDirectExpression(Expressions.LoopGroupBy);
    if (group) {
      new LoopGroupBy().runSyntax(group, input);
    }
 
  }
}