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

86.66% Statements 65/75
73.07% Branches 19/26
100% Functions 1/1
86.66% Lines 65/75

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 761x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1023x 1023x 1023x 1023x 1023x 1023x 1023x 751x 751x 752x 751x 751x 1x 1x 751x 1023x 1023x 751x 751x 751x 1x 1x 1x 1x 751x 1022x 1022x 1023x 1023x         1021x 1023x     1021x 1023x 271x 2x 2x 271x 271x 271x 1021x 1023x 7x         1023x 15x 15x 15x 15x 1023x 1023x 1x  
import * as Expressions from "../../2_statements/expressions";
import {StatementNode} from "../../nodes";
import {Source} from "../expressions/source";
import {Target} from "../expressions/target";
import {InlineData} from "../expressions/inline_data";
import {AbstractType} from "../../types/basic/_abstract_type";
import {StatementSyntax} from "../_statement_syntax";
import {TypeUtils} from "../_type_utils";
import {SyntaxInput, syntaxIssue} from "../_syntax_input";
import {Dereference} from "../expressions/dereference";
import {IdentifierMeta} from "../../types/_typed_identifier";
import {PackedType} from "../../types/basic";
 
export class Move implements StatementSyntax {
  public runSyntax(node: StatementNode, input: SyntaxInput): void {
    const targets = node.findDirectExpressions(Expressions.Target);
    const firstTarget = targets[0];
 
    const inline = firstTarget?.findDirectExpression(Expressions.InlineData);
 
    let targetType: AbstractType | undefined = undefined;
    if (inline === undefined) {
      targetType = firstTarget ? Target.runSyntax(firstTarget, input) : undefined;
      for (const t of targets) {
        if (t === firstTarget) {
          continue;
        }
        Target.runSyntax(t, input);
      }
    }
 
    if (inline === undefined && firstTarget !== undefined) {
// hmm, does this do the scoping correctly? handle constants etc? todo
      const found = input.scope.findVariable(firstTarget.concatTokens());
      if (found && found.getMeta().includes(IdentifierMeta.ReadOnly)) {
        const message = `"${firstTarget.concatTokens()}" cannot be modified, it is readonly`;
        input.issues.push(syntaxIssue(input, firstTarget.getFirstToken(), message));
        return;
      }
    }
 
    const source = node.findDirectExpression(Expressions.Source);
    let sourceType = source ? Source.runSyntax(source, input, targetType) : undefined;
    if (sourceType === undefined) {
      const message = "No source type determined";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    if (node.findDirectExpression(Expressions.Dereference)) {
      sourceType = Dereference.runSyntax(node, sourceType, input);
    }
 
    if (inline) {
      if (sourceType instanceof PackedType && source?.findDirectExpression(Expressions.ArithOperator)) {
        sourceType = new PackedType(8, 0);
      }
      InlineData.runSyntax(inline, input, sourceType);
      targetType = sourceType;
    }
 
    if (node.findDirectTokenByText("?=")) {
      if (new TypeUtils(input.scope).isCastable(sourceType, targetType) === false) {
        const message = "Incompatible types";
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        return;
      }
    } else if (new TypeUtils(input.scope).isAssignableNew(sourceType, targetType, source) === false) {
      const message = "Incompatible types";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
  }
}