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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 142x 142x 142x 142x 142x 55x 55x 142x 142x 142x 142x 142x 142x 142x 142x 142x 142x 142x 142x 1x 1x 1x 142x 141x 141x 141x 1x 1x 141x 140x 140x 140x 140x 140x 140x 140x 1x 1x 1x 142x 142x 142x 142x 142x 142x 142x 142x 1x 1x 1x 1x 141x 142x 124x 124x 124x 18x 18x 124x 141x 141x 142x 21x 21x 141x 141x 142x 142x 1x 1x 1x 1x 140x 140x 142x 142x 9x 9x 9x 9x 9x 9x 9x 9x 5x 5x 1x 1x 1x 1x 4x 5x 1x 1x 1x 1x 3x 5x 2x 2x 3x 1x 1x 1x 1x 3x 1x 5x 9x 137x 142x 142x 65x 65x 137x 142x 6x 6x 6x 137x 142x 142x 1x 142x 136x 136x 43x 43x 136x 137x 142x 1x 1x 137x 137x 142x 21x 21x 142x 142x 1x | import * as Expressions from "../../2_statements/expressions";
import {ExpressionNode, StatementNode} from "../../nodes";
import {VoidType, TableType, UnknownType, DataReference, AnyType, DataType, ITableKey, TableAccessType} 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";
import {Release, releaseAtLeast} from "../../../version";
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();
const topType = sourceType; // todo: refactor topType vs sourceType vs rowType
if (topType instanceof TableType
&& topType.getAccessType() === TableAccessType.hashed
&& node.findDirectTokenByText("USING") === undefined
&& (node.findDirectTokenByText("FROM") || node.findDirectTokenByText("TO"))) {
const message = "Implicit or explicit index operation on hashed table is not possible";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
if (sourceType instanceof TableType) {
rowType = sourceType.getRowType();
sourceType = rowType;
if (targetConcat?.startsWith("REFERENCE INTO ")) {
sourceType = new DataReference(sourceType);
}
}
const cond = node.findDirectExpression(Expressions.ComponentCond);
if (cond !== undefined) {
ComponentCond.runSyntax(cond, input, rowType);
}
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;
}
if (node.findDirectTokenByText("USING") !== undefined
&& cond !== undefined
&& topType instanceof TableType) {
// https://github.com/abap2xlsx/abap2xlsx/issues/1341
const keyName = node.findExpressionAfterToken("KEY");
let key: ITableKey | undefined = undefined;
const name = keyName?.get() instanceof Expressions.SimpleName ? keyName.getFirstToken().getStr().toUpperCase() : undefined;
// it might be dynamic, in that case we cannot check anything; and
// primary_key is the predefined name of the primary key every table has
if (name !== undefined && name !== "PRIMARY_KEY") {
key = topType.getOptions().secondary?.find(k => k.name.toUpperCase() === name);
if (key === undefined) {
const message = "Key " + keyName?.concatTokens() + " not found in table type";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
if (cond.findDirectTokenByText("OR") !== undefined) {
const message = "Loop, secondary key requires an optimizable WHERE, top-level OR not allowed";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
if (!releaseAtLeast(input.scope.getRelease(), Release.v740sp02)) {
const compares = cond.findAllExpressionsRecursive(Expressions.ComponentCompare).map(c => c.concatTokens().toUpperCase());
for (const keyField of key.keyFields) {
if (compares.find(c => c === keyField.toUpperCase() + " IS INITIAL") !== undefined) {
const message = "Loop, key check with IS INITIAL cannot optimized before 7.40 SP02";
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.Dynamic)) {
Dynamic.runSyntax(t, input);
}
const group = node.findDirectExpression(Expressions.LoopGroupBy);
if (group) {
LoopGroupBy.runSyntax(group, input);
}
}
} |