@abaplint/core 2.120.35 → 2.120.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3559,6 +3559,7 @@ export declare const enum IdentifierMeta {
3559
3559
  FunctionModuleTables = "function_module_tables",
3560
3560
  EventParameter = "event_parameter",
3561
3561
  FormParameter = "form_parameter",
3562
+ FormParameterStructure = "form_parameter_structure",
3562
3563
  ReadOnly = "read_only",
3563
3564
  Tables = "tables",
3564
3565
  Abstract = "abstract",
@@ -575,6 +575,29 @@ class TypeUtils {
575
575
  }
576
576
  return this.isAssignable(source, target);
577
577
  }
578
+ // Typing with the classic STRUCTURE addition, ie. "FORM foo USING bar STRUCTURE zkey",
579
+ // is not a compatibility check: ABAP only checks the fragment view up to the end of the
580
+ // formal structure, so the actual parameter is allowed to be longer. For TABLES parameters
581
+ // the table key is not part of the check at all.
582
+ isAssignableStructureTyping(source, target, node) {
583
+ if (source instanceof basic_1.StructureType && target instanceof basic_1.StructureType) {
584
+ const sourceComponents = source.getComponents();
585
+ const targetComponents = target.getComponents();
586
+ if (sourceComponents.length < targetComponents.length) {
587
+ return false;
588
+ }
589
+ for (let i = 0; i < targetComponents.length; i++) {
590
+ if (this.isAssignableStrict(sourceComponents[i].type, targetComponents[i].type) === false) {
591
+ return false;
592
+ }
593
+ }
594
+ return true;
595
+ }
596
+ else if (source instanceof basic_1.TableType && target instanceof basic_1.TableType) {
597
+ return this.isAssignableStructureTyping(source.getRowType(), target.getRowType());
598
+ }
599
+ return this.isAssignableStrict(source, target, node);
600
+ }
578
601
  isAssignable(source, target) {
579
602
  if (source === undefined || target === undefined) {
580
603
  return true;
@@ -533,7 +533,7 @@ class BasicTypes {
533
533
  return Types.VoidType.get((_f = node.findFirstExpression(Expressions.TypeStructure)) === null || _f === void 0 ? void 0 : _f.concatTokens());
534
534
  }
535
535
  else if (text.startsWith("LIKE LINE OF ")) {
536
- const name = (_g = node.findFirstExpression(Expressions.FieldChain)) === null || _g === void 0 ? void 0 : _g.concatTokens();
536
+ let name = (_g = node.findFirstExpression(Expressions.FieldChain)) === null || _g === void 0 ? void 0 : _g.concatTokens();
537
537
  let e = node.findFirstExpression(Expressions.Type);
538
538
  if (e === undefined) {
539
539
  e = node.findFirstExpression(Expressions.FormParamType);
@@ -541,19 +541,32 @@ class BasicTypes {
541
541
  if (e === undefined) {
542
542
  e = node.findFirstExpression(Expressions.FieldChain);
543
543
  }
544
+ if (e === undefined) {
545
+ // old style, eg "LIKE LINE OF tab OCCURS 0 WITH HEADER LINE", it is parsed as TypeName
546
+ e = typeName;
547
+ name = typeName === null || typeName === void 0 ? void 0 : typeName.concatTokens();
548
+ }
544
549
  const type = this.resolveLikeName(e, false);
550
+ let row = undefined;
545
551
  if (type === undefined) {
546
552
  return new Types.UnknownType("Type error, could not resolve \"" + name + "\", parseType");
547
553
  }
548
554
  else if (type instanceof Types.TableType) {
549
- return type.getRowType();
555
+ row = type.getRowType();
550
556
  }
551
557
  else if (type instanceof Types.VoidType) {
552
- return type;
558
+ row = type;
553
559
  }
554
560
  else {
555
561
  return new Types.UnknownType("Type error, not a table type " + name);
556
562
  }
563
+ if (this.isOccurs(node)) {
564
+ return new Types.TableType(row, {
565
+ withHeader: text.includes(" WITH HEADER LINE"),
566
+ keyType: Types.TableKeyType.default
567
+ }, qualifiedName);
568
+ }
569
+ return row;
557
570
  }
558
571
  else if (text.startsWith("LIKE REF TO ")) {
559
572
  const name = (_h = node.findFirstExpression(Expressions.FieldChain)) === null || _h === void 0 ? void 0 : _h.concatTokens();
@@ -31,7 +31,7 @@ class FormParam {
31
31
  else {
32
32
  type = new basic_1.UnknownType("todo, FORM STRUCTURES typing");
33
33
  }
34
- return new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, type, ["form_parameter" /* IdentifierMeta.FormParameter */]);
34
+ return new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, type, ["form_parameter" /* IdentifierMeta.FormParameter */, "form_parameter_structure" /* IdentifierMeta.FormParameterStructure */]);
35
35
  }
36
36
  if (node.getChildren().length === 1 && nameToken) {
37
37
  // untyped FORM parameter
@@ -113,7 +113,11 @@ class Perform {
113
113
  continue;
114
114
  }
115
115
  const parameter = formal[i];
116
- if (typeUtils.isAssignableStrict(type, parameter.getType(), source) === false) {
116
+ const structureTyping = parameter.getMeta().includes("form_parameter_structure" /* IdentifierMeta.FormParameterStructure */);
117
+ const assignable = structureTyping
118
+ ? typeUtils.isAssignableStructureTyping(type, parameter.getType(), source)
119
+ : typeUtils.isAssignableStrict(type, parameter.getType(), source);
120
+ if (assignable === false) {
117
121
  const message = `PERFORM parameter type not compatible, ${parameter.getName()}`;
118
122
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, source.getFirstToken(), message));
119
123
  return false;
@@ -90,7 +90,8 @@ class FormDefinition extends _identifier_1.Identifier {
90
90
  else if (!(type instanceof basic_1.UnknownType) && !(type instanceof basic_1.VoidType)) {
91
91
  type = new basic_1.UnknownType("FORM TABLES type must be table type");
92
92
  }
93
- ret.push(new _typed_identifier_1.TypedIdentifier(p.getToken(), input.filename, type, ["form_parameter" /* IdentifierMeta.FormParameter */]));
93
+ // keep the meta from FormParam, so STRUCTURE typing can be recognized later
94
+ ret.push(new _typed_identifier_1.TypedIdentifier(p.getToken(), input.filename, type, p.getMeta()));
94
95
  }
95
96
  }
96
97
  return ret;
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.35";
78
+ return "2.120.37";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.120.35",
3
+ "version": "2.120.37",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",