All files / src/abap/5_syntax/expressions value_body.ts

96.11% Statements 99/103
93.33% Branches 42/45
100% Functions 1/1
96.11% Lines 99/103

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 1031x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 173x 173x 173x 173x 173x 54x 54x 119x 119x 119x 173x 9x 9x 119x 119x 173x 34x 34x 33x 33x 34x 118x 118x 173x 55x 55x 55x 51x 51x 51x 51x 1x 1x 1x 1x 50x 50x 51x 55x 117x 117x 173x 7x 7x 173x 19x 19x 117x 173x 78x 78x 78x 78x 78x         78x 78x 60x 60x 78x 78x 4x 5x 5x 5x 4x 78x 50x 50x 78x 39x 39x 78x 117x 173x 9x 9x 117x 173x 33x 33x 117x 173x 1x 1x 173x 173x 1x
import {ExpressionNode} from "../../nodes";
import * as Expressions from "../../2_statements/expressions";
import {For} from "./for";
import {Source} from "./source";
import {AbstractType} from "../../types/basic/_abstract_type";
import {Let} from "./let";
import {FieldAssignment} from "./field_assignment";
import {AnyType, TableType, UnknownType, VoidType} from "../../types/basic";
import {CheckSyntaxKey, SyntaxInput, syntaxIssue} from "../_syntax_input";
 
export class ValueBody {
  public static runSyntax(
    node: ExpressionNode | undefined,
    input: SyntaxInput,
    targetType: AbstractType | undefined): AbstractType | undefined {
 
    if (node === undefined) {
      return targetType;
    }
 
    let letScoped = false;
    const letNode = node.findDirectExpression(Expressions.Let);
    if (letNode) {
      letScoped = Let.runSyntax(letNode, input);
    }
 
    let forScopes = 0;
    for (const forNode of node.findDirectExpressions(Expressions.For) || []) {
      const scoped = For.runSyntax(forNode, input);
      if (scoped === true) {
        forScopes++;
      }
    }
 
    const fields = new Set<string>();
    for (const s of node.findDirectExpressions(Expressions.FieldAssignment)) {
      FieldAssignment.runSyntax(s, input, targetType);
 
      if (node.findDirectExpression(Expressions.ValueBodyLine) === undefined) {
        // todo: refine, still needs to be checked when there are table lines
        const fieldname = s.findDirectExpression(Expressions.FieldSub)?.concatTokens().toUpperCase();
        if (fieldname) {
          if (fields.has(fieldname)) {
            const message = "Duplicate field assignment";
            input.issues.push(syntaxIssue(input, s.getFirstToken(), message));
            return VoidType.get(CheckSyntaxKey);
          }
          fields.add(fieldname);
        }
      }
    }
 
    let type: AbstractType | undefined = undefined; // todo, this is only correct if there is a single source in the body
    for (const s of node.findDirectExpressions(Expressions.Source)) {
      type = Source.runSyntax(s, input, type);
    }
    for (const s of node.findDirectExpression(Expressions.ValueBase)?.findDirectExpressions(Expressions.Source) || []) {
      type = Source.runSyntax(s, input, type);
    }
 
    for (const foo of node.findDirectExpressions(Expressions.ValueBodyLine)) {
      if (!(targetType instanceof TableType)
          && !(targetType instanceof UnknownType)
          && !(targetType instanceof AnyType)
          && targetType !== undefined
          && !(targetType instanceof VoidType)) {
        const message = "Value, not a table type";
        input.issues.push(syntaxIssue(input, foo.getFirstToken(), message));
        return VoidType.get(CheckSyntaxKey);
      }
      let rowType: AbstractType | undefined = targetType;
      if (targetType instanceof TableType) {
        rowType = targetType.getRowType();
      }
 
      for (const l of foo.findDirectExpressions(Expressions.ValueBodyLines)) {
        for (const s of l.findDirectExpressions(Expressions.Source)) {
// LINES OF ?? todo, pass type,
          Source.runSyntax(s, input);
        }
      }
      for (const s of foo.findDirectExpressions(Expressions.FieldAssignment)) {
        FieldAssignment.runSyntax(s, input, rowType);
      }
      for (const s of foo.findDirectExpressions(Expressions.Source)) {
        Source.runSyntax(s, input, rowType);
      }
    }
 
    if (letScoped === true) {
      input.scope.pop(node.getLastToken().getEnd());
    }
 
    for (let i = 0; i < forScopes; i++) {
      input.scope.pop(node.getLastToken().getEnd());
    }
 
    if (targetType?.isGeneric() && type) {
      return type;
    }
    return targetType ? targetType : type;
  }
}