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

92.5% Statements 111/120
91.8% Branches 56/61
100% Functions 1/1
92.5% Lines 111/120

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 1201x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 131x 131x 131x 131x 131x 51x 51x 131x 131x 131x 131x 131x 131x 1x 1x 131x 131x 131x 131x 131x 1x 1x       131x 1x 1x 1x 130x 129x 129x 129x 1x 1x 129x 128x 128x 128x 128x     128x 128x 128x 1x 1x 1x 131x 131x 131x 106x 106x 106x 18x 18x 106x 131x 131x 131x 131x 1x 1x 1x 1x 130x 131x 131x 59x 59x 130x 131x 6x     6x 6x 130x 131x 131x 1x 131x 129x 129x 39x 39x 129x 130x 131x 10x 10x 130x 131x     130x 130x 131x 21x 21x 131x 131x 1x
import * as Expressions from "../../2_statements/expressions";
import {ExpressionNode, 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 ? 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.LoopSource)?.getFirstChild() as ExpressionNode | undefined;
    if (firstSource === undefined) {
      firstSource = sources[0];
    }
    let sourceType = firstSource ? 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));
      }
    } else if (sourceType instanceof UnknownType) {
      const message = "Loop, not a table type, " + sourceType.getError();
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      sourceType = VoidType.get("Loop, not a table type");
    } 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));
    } 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));
    } else if (loopTarget === undefined
        && sourceType instanceof TableType
        && sourceType.isWithHeader() === false) {
      const message = "Loop, no header";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
    }
 
    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) {
      InlineData.runSyntax(inline, input, sourceType);
    }
 
    for (const s of sources) {
      if (s === firstSource) {
        continue;
      }
      Source.runSyntax(s, input);
    }
 
    const inlinefs = target?.findDirectExpression(Expressions.InlineFS);
    if (inlinefs) {
      InlineFS.runSyntax(inlinefs, input, sourceType);
    } else {
      const fstarget = loopTarget?.findDirectExpression(Expressions.FSTarget);
      if (fstarget) {
        FSTarget.runSyntax(fstarget, input, sourceType);
      }
    }
 
    for (const t of node.findDirectExpressions(Expressions.ComponentCond)) {
      ComponentCond.runSyntax(t, input, rowType);
    }
 
    for (const t of node.findDirectExpressions(Expressions.Dynamic)) {
      Dynamic.runSyntax(t, input);
    }
 
    const group = node.findDirectExpression(Expressions.LoopGroupBy);
    if (group) {
      LoopGroupBy.runSyntax(group, input);
    }
 
  }
}