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

95.23% Statements 80/84
89.28% Branches 25/28
100% Functions 3/3
95.23% Lines 80/84

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 841x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 19x 19x     19x 19x 19x 19x 2x 2x 2x 19x 19x 1x 1x 1x 1x 18x 19x 1x 1x 1x 1x 17x 17x 19x 2x 2x 2x 17x 19x 1x 1x 1x 1x 16x 16x 16x 16x 19x     16x 16x 16x 16x 16x 1x 1x 1x 17x 17x 109x 109x 109x 2x 2x 109x 15x 15x 1x 1x 1x 2x 2x 19x 19x 1x 1x 19x 1x 1x 1x
import * as Expressions from "../../2_statements/expressions";
import {StatementNode} from "../../nodes";
import {TypedIdentifier} from "../../types/_typed_identifier";
import {UnknownType, VoidType} from "../../types/basic";
import {BasicTypes} from "../basic_types";
import {StatementSyntax} from "../_statement_syntax";
import {SyntaxInput, syntaxIssue} from "../_syntax_input";
import {Identifier} from "../../1_lexer/tokens";
 
export class Parameter implements StatementSyntax {
  public runSyntax(node: StatementNode, input: SyntaxInput): void {
    const nameExpression = node.findFirstExpression(Expressions.FieldSub);
    if (nameExpression === undefined) {
      return;
    }
 
    let nameToken = nameExpression.getFirstToken();
    // FieldSub can include dashes and optional length, eg p-tcode or p_table(4).
    if (nameExpression.getChildren().length > 1) {
      const fullName = nameExpression.concatTokens().replace(/\(.+$/, "").replace(/\[\]$/, "");
      nameToken = new Identifier(nameToken.getStart(), fullName);
    }
 
    if (nameToken && nameToken.getStr().length > 8) {
      const message = "Parameter name too long, " + nameToken.getStr();
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    if (node.findDirectTokenByText("RADIOBUTTON") && node.findDirectTokenByText("LENGTH")) {
      const message = "RADIOBUTTON and LENGTH not possible together";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    const radioGroup = node.findFirstExpression(Expressions.RadioGroupName);
    if (radioGroup && radioGroup.concatTokens().length > 4) {
      const message = "Radio button group name too long, " + radioGroup.concatTokens();
      input.issues.push(syntaxIssue(input, radioGroup.getFirstToken(), message));
    }
 
    if (this.hasUserCommand(node) && this.hasLength(node)) {
      const message = "USER-COMMAND and LENGTH not possible together";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    const bfound = new BasicTypes(input).parseType(node);
    if (bfound) {
      input.scope.addIdentifier(new TypedIdentifier(nameToken, input.filename, bfound));
    } else {
      input.scope.addIdentifier(new TypedIdentifier(nameToken, input.filename, new UnknownType("Parameter, fallback")));
    }
 
    const magicName = "%_" + nameToken.getStr() + "_%_app_%";
    const magicToken = new Identifier(nameToken.getStart(), magicName);
    input.scope.addIdentifier(new TypedIdentifier(magicToken, input.filename, VoidType.get("PARAMETER-MAGIC")));
  }
 
  // "USER-COMMAND" is lexed as three tokens
  private hasUserCommand(node: StatementNode): boolean {
    const tokens = node.getTokens();
    for (let i = 0; i < tokens.length - 2; i++) {
      if (tokens[i].getStr().toUpperCase() === "USER"
          && tokens[i + 1].getStr() === "-"
          && tokens[i + 2].getStr().toUpperCase() === "COMMAND") {
        return true;
      }
    }
    return false;
  }
 
  // "VISIBLE LENGTH" is not the same as "LENGTH"
  private hasLength(node: StatementNode): boolean {
    const tokens = node.getTokens();
    for (let i = 0; i < tokens.length; i++) {
      if (tokens[i].getStr().toUpperCase() === "LENGTH"
          && tokens[i - 1]?.getStr().toUpperCase() !== "VISIBLE") {
        return true;
      }
    }
    return false;
  }
}