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

92.43% Statements 110/119
78.72% Branches 37/47
100% Functions 1/1
92.43% Lines 110/119

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 1191x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 78x 78x 78x 78x 78x 1x 1x 78x 78x 78x   78x 1x 1x 76x 76x 78x 70x 70x 76x 76x 78x 49x 49x 72x 72x 78x 25x 25x 1x 1x 25x 70x 70x 78x 1x 1x     1x 70x 70x 78x 26x 25x 25x 1x 1x 1x 1x 1x 1x 26x 69x 69x 78x 68x 2x 2x 68x 68x 68x 68x 68x 9x 68x 18x 59x 14x 14x 2x 2x 14x 68x 65x 78x 1x 1x 1x 1x 1x 64x 64x 64x 78x 78x 78x 1x     1x 1x 1x       1x 1x 1x 1x   78x 78x 1x
import * as Expressions from "../../2_statements/expressions";
import {StatementNode} from "../../nodes";
import {CurrentScope} from "../_current_scope";
import {VoidType, TableType, IntegerType, DataReference, AnyType, UnknownType, StructureType, ObjectReferenceType, StringType} from "../../types/basic";
import {Source} from "../expressions/source";
import {InlineData} from "../expressions/inline_data";
import {Target} from "../expressions/target";
import {FSTarget} from "../expressions/fstarget";
import {ComponentCompareSimple} from "../expressions/component_compare_simple";
import {StatementSyntax} from "../_statement_syntax";
import {AbstractType} from "../../types/basic/_abstract_type";
import {TypeUtils} from "../_type_utils";
 
export class ReadTable implements StatementSyntax {
  public runSyntax(node: StatementNode, scope: CurrentScope, filename: string): void {
    const concat = node.concatTokens().toUpperCase();
    const sources = node.findDirectExpressions(Expressions.Source);
 
    let firstSource = node.findDirectExpression(Expressions.SimpleSource2);
    if (firstSource === undefined) {
      firstSource = sources[0];
    }
    const sourceType = firstSource ? new Source().runSyntax(firstSource, scope, filename) : undefined;
 
    if (sourceType === undefined) {
      throw new Error("No source type determined, read table");
    } else if (!(sourceType instanceof TableType) && !(sourceType instanceof VoidType)) {
      throw new Error("Read table, not a table type");
    }
 
    let rowType: AbstractType = sourceType;
    if (rowType instanceof TableType) {
      rowType = rowType.getRowType();
    }
 
    const components = node.findDirectExpression(Expressions.ComponentCompareSimple);
    if (components !== undefined) {
      new ComponentCompareSimple().runSyntax(components, scope, filename, rowType);
    }
 
    const indexSource = node.findExpressionAfterToken("INDEX");
    if (indexSource) {
      const indexType = new Source().runSyntax(indexSource, scope, filename);
      if (new TypeUtils(scope).isAssignable(indexType, IntegerType.get()) === false) {
        throw new Error("READ TABLE, INDEX must be simple");
      }
    }
 
    const fromSource = node.findExpressionAfterToken("FROM");
    if (fromSource) {
      const fromType = new Source().runSyntax(fromSource, scope, filename);
      if (new TypeUtils(scope).isAssignable(fromType, rowType) === false) {
        throw new Error("READ TABLE, FROM must be compatible");
      }
    }
 
    const afterKey = node.findExpressionAfterToken("KEY");
    for (const s of sources) {
      if (s === firstSource || s === indexSource || s === fromSource) {
        continue;
      }
      const type = new Source().runSyntax(s, scope, filename);
      if (s === afterKey) {
        if (type instanceof StringType || type instanceof TableType || type instanceof ObjectReferenceType) {
          throw new Error("Key cannot be string or table or reference");
        }
      }
    }
 
    const target = node.findDirectExpression(Expressions.ReadTableTarget);
    if (target) {
      if (concat.includes(" REFERENCE INTO ")) {
        rowType = new DataReference(rowType);
      }
 
      const inline = target.findFirstExpression(Expressions.InlineData);
      const fst = target.findDirectExpression(Expressions.FSTarget);
      const t = target.findFirstExpression(Expressions.Target);
      if (inline) {
        new InlineData().runSyntax(inline, scope, filename, rowType);
      } else if (fst) {
        new FSTarget().runSyntax(fst, scope, filename, rowType);
      } else if (t) {
        const targetType = new Target().runSyntax(t, scope, filename);
        if (new TypeUtils(scope).isAssignable(rowType, targetType) === false) {
          throw new Error("Incompatible types");
        }
      }
    }
 
    if (target === undefined && concat.includes(" TRANSPORTING NO FIELDS ") === false) {
      // if sourceType is void, assume its with header
      if (sourceType instanceof TableType && sourceType.isWithHeader() === false) {
        throw new Error("READ TABLE, define INTO or TRANSPORTING NO FIELDS");
      }
    }
 
    const transporting = node.findDirectExpression(Expressions.TransportingFields);
    if (transporting
        && !(rowType instanceof VoidType)
        && !(rowType instanceof UnknownType)
        && !(rowType instanceof AnyType)) {
      if (!(rowType instanceof StructureType)) {
        throw new Error("READ TABLE, source not structured");
      }
      for (const t of transporting?.findDirectExpressions(Expressions.FieldSub) || []) {
        const field = t.concatTokens();
        if (field.includes("-")) {
          // todo
          continue;
        }
        if (rowType.getComponentByName(field) === undefined) {
          throw new Error("READ TABLE, field " + field + " not found in source");
        }
      }
    }
 
  }
}