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

85.91% Statements 61/71
73.91% Branches 17/23
100% Functions 1/1
85.91% Lines 61/71

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 711x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 941x 941x 941x 941x 941x 941x 941x 693x 693x 694x 693x 693x 1x 1x 693x 941x 941x 693x 693x 693x 1x 1x 1x 1x 693x 940x 940x 941x 941x         939x 941x     939x 941x 247x 247x 247x 939x 941x 5x         941x 14x 14x 14x 14x 941x 941x 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";
 
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) {
      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;
    }
 
  }
}