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

89.43% Statements 127/142
82.35% Branches 42/51
100% Functions 1/1
89.43% Lines 127/142

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 1421x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 91x 91x 91x 91x 91x 91x 91x       91x 1x 91x 1x 1x 1x 1x 90x 90x 91x 82x 82x 90x 90x 91x 53x 53x 90x 90x 91x 34x 34x 1x 1x 1x 34x 1x 1x 1x 1x 34x 88x 88x 91x 1x 1x         1x 88x 88x 91x 123x 121x 121x 2x 2x 2x 2x 2x 1x 1x 1x 1x 2x 123x 87x 87x 91x 85x 2x 2x 85x 85x 85x 85x 85x 10x 85x 28x 75x 13x 13x 2x 2x 2x 2x 13x 85x 85x 91x 2x 2x 1x 1x 1x 1x 2x 84x 84x 84x 91x 91x 91x 1x         1x 1x 1x       1x 1x 1x 1x 1x 1x   91x 91x 1x
import * as Expressions from "../../2_statements/expressions";
import {StatementNode} from "../../nodes";
import {VoidType, TableType, IntegerType, DataReference, AnyType, UnknownType, StructureType, ObjectReferenceType, StringType, TableAccessType} 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";
import {SyntaxInput, syntaxIssue} from "../_syntax_input";
 
export class ReadTable implements StatementSyntax {
  public runSyntax(node: StatementNode, input: SyntaxInput): void {
    const concat = node.concatTokens().toUpperCase();
    const sources = node.findDirectExpressionsMulti([Expressions.Source, Expressions.SimpleSource2]);
 
    const firstSource = sources[0];
    const sourceType = firstSource ? Source.runSyntax(firstSource, input) : undefined;
 
    if (sourceType === undefined) {
      const message = "No source type determined, read table";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    } else if (sourceType instanceof UnknownType) {
      // do nothing, ok
    } else if (!(sourceType instanceof TableType) && !(sourceType instanceof VoidType)) {
      const message = "Read table, not a table type";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    let rowType: AbstractType = sourceType;
    if (rowType instanceof TableType) {
      rowType = rowType.getRowType();
    }
 
    const components = node.findDirectExpression(Expressions.ComponentCompareSimple);
    if (components !== undefined) {
      ComponentCompareSimple.runSyntax(components, input, rowType);
    }
 
    const indexSource = node.findExpressionAfterToken("INDEX");
    if (indexSource) {
      const indexType = Source.runSyntax(indexSource, input);
      if (new TypeUtils(input.scope).isAssignable(indexType, IntegerType.get()) === false) {
        const message = "READ TABLE, INDEX must be simple, got " + indexType?.constructor.name;
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        return;
      } else if (sourceType instanceof TableType && sourceType.getAccessType() === TableAccessType.hashed) {
        const message = "INDEX on hashed table not possible";
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        return;
      }
    }
 
    const fromSource = node.findExpressionAfterToken("FROM");
    if (fromSource) {
      const fromType = Source.runSyntax(fromSource, input);
      if (new TypeUtils(input.scope).isAssignable(fromType, rowType) === false) {
        const message = "READ TABLE, FROM must be compatible";
        input.issues.push(syntaxIssue(input, fromSource.getFirstToken(), message));
        return;
      }
    }
 
    const afterKey = node.findExpressionAfterToken("KEY");
    for (const s of sources) {
      if (s === firstSource || s === indexSource || s === fromSource) {
        continue;
      }
      const type = Source.runSyntax(s, input);
      if (s === afterKey) {
        if (type instanceof StringType
            || (type instanceof TableType && type.isWithHeader() === false)
            || type instanceof ObjectReferenceType) {
          const message = "Key cannot be string or table or reference";
          input.issues.push(syntaxIssue(input, s.getFirstToken(), message));
          return;
        }
      }
    }
 
    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) {
        InlineData.runSyntax(inline, input, rowType);
      } else if (fst) {
        FSTarget.runSyntax(fst, input, rowType);
      } else if (t) {
        const targetType = Target.runSyntax(t, input);
        if (new TypeUtils(input.scope).isAssignable(rowType, targetType) === false) {
          const message = "Incompatible types";
          input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
          return;
        }
      }
    }
 
    if (target === undefined && concat.includes(" TRANSPORTING NO FIELDS ") === false) {
      // if sourceType is void, assume its with header
      if (sourceType instanceof TableType && sourceType.isWithHeader() === false) {
        const message = "READ TABLE, define INTO or TRANSPORTING NO FIELDS";
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        return;
      }
    }
 
    const transporting = node.findDirectExpression(Expressions.TransportingFields);
    if (transporting
        && !(rowType instanceof VoidType)
        && !(rowType instanceof UnknownType)
        && !(rowType instanceof AnyType)) {
      if (!(rowType instanceof StructureType)) {
        const message = "READ TABLE, source not structured";
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        return;
      }
      for (const t of transporting?.findDirectExpressions(Expressions.FieldSub) || []) {
        const field = t.concatTokens();
        if (field.includes("-")) {
          // todo
          continue;
        }
        if (rowType.getComponentByName(field) === undefined) {
          const message = "READ TABLE, field " + field + " not found in source";
          input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
          return;
        }
      }
    }
 
  }
}