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

86.66% Statements 78/90
72.72% Branches 24/33
100% Functions 1/1
86.66% Lines 78/90

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 901x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 92x 92x 92x 92x 92x 92x 92x 92x 92x 92x 6x     6x 6x 6x 91x 91x 92x 3x     3x 3x 3x 91x 91x 92x 37x 37x 92x 64x 64x 64x 64x     64x 64x 64x 62x 64x 1x 1x 64x 64x 64x 5x 5x 5x 5x 5x 5x 5x 5x     64x 56x 1x 1x 56x 64x 87x 87x 92x     87x 92x     92x 92x 1x
import * as Expressions from "../../2_statements/expressions";
import {StatementNode} from "../../nodes";
import {CurrentScope} from "../_current_scope";
import {Source} from "../expressions/source";
import {Target} from "../expressions/target";
import {DataReference, TableType, VoidType} from "../../types/basic";
import {AbstractType} from "../../types/basic/_abstract_type";
import {FSTarget} from "../expressions/fstarget";
import {StatementSyntax} from "../_statement_syntax";
import {InlineData} from "../expressions/inline_data";
import {TypeUtils} from "../_type_utils";
 
// todo: issue error for short APPEND if the source is without header line
export class Append implements StatementSyntax {
  public runSyntax(node: StatementNode, scope: CurrentScope, filename: string): void {
 
    let targetType: AbstractType | undefined = undefined;
 
    const target = node.findDirectExpression(Expressions.Target);
    if (target) {
      targetType = new Target().runSyntax(target, scope, filename);
    }
 
    const fsTarget = node.findExpressionAfterToken("ASSIGNING");
    if (fsTarget && fsTarget.get() instanceof Expressions.FSTarget) {
      if (!(targetType instanceof TableType) && !(targetType instanceof VoidType)) {
        throw new Error("APPEND to non table type");
      }
      const rowType = targetType instanceof TableType ? targetType.getRowType() : targetType;
      new FSTarget().runSyntax(fsTarget, scope, filename, rowType);
    }
 
    const dataTarget = node.findExpressionAfterToken("INTO");
    if (dataTarget && node.concatTokens().toUpperCase().includes(" REFERENCE INTO DATA(")) {
      if (!(targetType instanceof TableType) && !(targetType instanceof VoidType)) {
        throw new Error("APPEND to non table type");
      }
      const rowType = targetType instanceof TableType ? targetType.getRowType() : targetType;
      new InlineData().runSyntax(dataTarget, scope, filename, new DataReference(rowType));
    }
 
    let source = node.findDirectExpression(Expressions.SimpleSource4);
    if (source === undefined) {
      source = node.findDirectExpression(Expressions.Source);
    }
    if (source) {
      if (targetType !== undefined
          && !(targetType instanceof TableType)
          && dataTarget !== target
          && !(targetType instanceof VoidType)) {
        throw new Error("Append, target not a table type");
      }
 
      let rowType: AbstractType | undefined = undefined;
      if (targetType instanceof TableType) {
        rowType = targetType.getRowType();
      } else if (targetType instanceof VoidType) {
        rowType = targetType;
      }
      let sourceType = new Source().runSyntax(source, scope, filename, rowType);
 
      if (node.findDirectTokenByText("LINES")) {
        // hmm, checking only the row types are compatible will not check the table type, e.g. sorted or hashed
        if (sourceType instanceof TableType) {
          sourceType = sourceType.getRowType();
        }
        if (targetType instanceof TableType) {
          targetType = targetType.getRowType();
        }
        if (new TypeUtils(scope).isAssignable(sourceType, targetType) === false) {
          throw new Error("Incompatible types");
        }
      } else {
        if (new TypeUtils(scope).isAssignable(sourceType, rowType) === false) {
          throw new Error("Incompatible types");
        }
      }
    }
 
    const from = node.findExpressionAfterToken("FROM");
    if (from && from.get() instanceof Expressions.Source) {
      new Source().runSyntax(from, scope, filename);
    }
    const to = node.findExpressionAfterToken("TO");
    if (to && to.get() instanceof Expressions.Source) {
      new Source().runSyntax(to, scope, filename);
    }
 
  }
}