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

89.44% Statements 144/161
80.51% Branches 62/77
100% Functions 2/2
89.44% Lines 144/161

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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 1611x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1285x 1285x 1285x 152x 152x 152x 1x 1x 1x 152x 1284x 1284x 1284x 1285x     1284x 1284x 1285x 51x 51x 1232x 1285x 306x 306x     306x 306x 133x   133x 133x 133x 133x     306x 11x 11x 11x 8x 8x 173x 3x     3x 3x 2x 2x 162x 133x 159x 3x 3x 3x 3x     3x 2x 2x 26x 23x 3x     3x 3x 3x 3x 23x 6x 6x 6x 306x 1223x 1223x 1285x 5x 2x 2x 3x 3x 1220x 1220x 1285x 5x 2x 2x 3x 3x 1218x 1218x 1218x 1x 1x 1x 1x 1284x     1284x 1284x 1284x 1284x 1284x 1284x 1171x 1171x 1120x 1120x 1171x 2x 2x 2x 2x 2x 1171x 1284x 3x 3x 2x 2x 3x 1x 1x 1x     113x 2x 2x 1x 1x 1x 1x 108x 108x 108x 1x
import * as Expressions from "../../2_statements/expressions";
import {ExpressionNode} from "../../nodes";
import {CurrentScope} from "../_current_scope";
import {AbstractType} from "../../types/basic/_abstract_type";
import {UnknownType} from "../../types/basic/unknown_type";
import {INode} from "../../nodes/_inode";
import {Dash, InstanceArrow} from "../../1_lexer/tokens";
import {StructureType, ObjectReferenceType, VoidType, DataReference, TableType, XStringType, StringType} from "../../types/basic";
import {ComponentName} from "./component_name";
import {AttributeName} from "./attribute_name";
import {FieldOffset} from "./field_offset";
import {ReferenceType} from "../_reference";
import {TableExpression} from "./table_expression";
import {Dereference} from "../../2_statements/expressions";
import {FieldLength} from "./field_length";
import {Cast} from "./cast";
 
export class Target {
  public runSyntax(node: ExpressionNode, scope: CurrentScope, filename: string): AbstractType | undefined {
 
    const concat = node.concatTokens();
    if (concat.includes("-")) {
      // workaround for names with dashes
      const found = scope.findVariable(concat);
      if (found) {
        scope.addReference(node.getFirstToken(), found, ReferenceType.DataWriteReference, filename);
        return found.getType();
      }
    }
 
    const children = node.getChildren().slice();
    const first = children.shift();
    if (first === undefined || !(first instanceof ExpressionNode)) {
      return undefined;
    }
 
    let context = this.findTop(first, scope, filename);
    if (context === undefined) {
      throw new Error(`"${first.getFirstToken().getStr()}" not found, Target`);
    }
 
    while (children.length > 0) {
      const current = children.shift();
      if (current === undefined) {
        break;
      }
 
      if (current.get() instanceof Dash) {
        if (context instanceof UnknownType) {
          throw new Error("Not a structure, type unknown, target");
        } else if (!(context instanceof StructureType)
            && !(context instanceof TableType && context.isWithHeader() && context.getRowType() instanceof StructureType)
            && !(context instanceof TableType && context.isWithHeader() && context.getRowType() instanceof VoidType)
            && !(context instanceof VoidType)) {
          throw new Error("Not a structure, target");
        }
      } else if (current.get() instanceof InstanceArrow) {
        if (!(context instanceof ObjectReferenceType)
            && !(context instanceof DataReference)
            && !(context instanceof VoidType)) {
          throw new Error("Not an object reference, target");
        }
      } else if (current.get() instanceof Dereference) {
        if (!(context instanceof DataReference) && !(context instanceof VoidType)) {
          throw new Error("Not an object reference, target");
        }
 
        if (!(context instanceof VoidType)) {
          context = context.getType();
        }
      } else if (current.get() instanceof Expressions.ComponentName) {
        context = new ComponentName().runSyntax(context, current);
      } else if (current.get() instanceof Expressions.TableBody) {
        if (!(context instanceof TableType)
            && !(context instanceof VoidType)
            && !(context instanceof UnknownType)
            && !(context instanceof UnknownType)) {
          throw new Error("Not a internal table, \"[]\"");
        }
        if (context instanceof TableType && context.isWithHeader()) {
          context = new TableType(context.getRowType(), {...context.getOptions(), withHeader: false});
        }
      } else if (current instanceof ExpressionNode
          && current.get() instanceof Expressions.TableExpression) {
        if (!(context instanceof TableType) && !(context instanceof VoidType)) {
          throw new Error("Table expression, expected table");
        }
        new TableExpression().runSyntax(current, scope, filename);
        if (!(context instanceof VoidType)) {
          context = context.getRowType();
        }
      } else if (current.get() instanceof Expressions.AttributeName) {
        const type = children.length === 0 ? ReferenceType.DataWriteReference : ReferenceType.DataReadReference;
        context = new AttributeName().runSyntax(context, current, scope, filename, type);
      }
    }
 
    const offset = node.findDirectExpression(Expressions.FieldOffset);
    if (offset) {
      if (context instanceof XStringType || context instanceof StringType) {
        throw new Error("xstring/string offset/length in writer position not possible");
      }
      new FieldOffset().runSyntax(offset, scope, filename);
    }
 
    const length = node.findDirectExpression(Expressions.FieldLength);
    if (length) {
      if (context instanceof XStringType || context instanceof StringType) {
        throw new Error("xstring/string offset/length in writer position not possible");
      }
      new FieldLength().runSyntax(length, scope, filename);
    }
 
    return context;
  }
 
/////////////////////////////////
 
  private findTop(node: INode | undefined, scope: CurrentScope, filename: string): AbstractType | undefined {
    if (node === undefined) {
      return undefined;
    }
 
    const token = node.getFirstToken();
    const name = token.getStr();
 
    if (node.get() instanceof Expressions.TargetField
        || node.get() instanceof Expressions.TargetFieldSymbol) {
      const found = scope.findVariable(name);
      if (found) {
        scope.addReference(token, found, ReferenceType.DataWriteReference, filename);
      }
      if (name.includes("~")) {
        const idef = scope.findInterfaceDefinition(name.split("~")[0]);
        if (idef) {
          scope.addReference(token, idef, ReferenceType.ObjectOrientedReference, filename);
        }
      }
      return found?.getType();
    } else if (node.get() instanceof Expressions.ClassName) {
      const found = scope.findObjectDefinition(name);
      if (found) {
        scope.addReference(token, found, ReferenceType.ObjectOrientedReference, filename);
        return new ObjectReferenceType(found);
      } else if (scope.getDDIC().inErrorNamespace(name) === false) {
        scope.addReference(token, undefined, ReferenceType.ObjectOrientedVoidReference, filename, {ooName: name, ooType: "CLAS"});
        return new VoidType(name);
      } else {
        return new UnknownType(name + " unknown, Target");
      }
    } else if (node.get() instanceof Expressions.Cast && node instanceof ExpressionNode) {
      const ret = new Cast().runSyntax(node, scope, undefined, filename);
      if (ret instanceof UnknownType) {
        throw new Error("CAST, uknown type");
      }
      return ret;
    }
 
    return new UnknownType("unknown target type");
  }
}