@abaplint/core 2.120.73 → 2.120.75

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.
Files changed (45) hide show
  1. package/build/abaplint.d.ts +6 -1
  2. package/build/src/abap/2_statements/combi.js +143 -51
  3. package/build/src/abap/2_statements/expressions/method_param_optional.js +3 -1
  4. package/build/src/abap/5_syntax/basic_types.js +67 -23
  5. package/build/src/abap/5_syntax/statements/append.js +6 -0
  6. package/build/src/abap/types/method_definition.js +22 -0
  7. package/build/src/abap/types/method_parameters.js +57 -0
  8. package/build/src/ddic.js +1 -1
  9. package/build/src/objects/data_definition.js +9 -1
  10. package/build/src/objects/domain.js +4 -1
  11. package/build/src/registry.js +1 -1
  12. package/build/src/rules/abapdoc_html_tag.js +123 -0
  13. package/build/src/rules/abapdoc_leading_at.js +117 -0
  14. package/build/src/rules/abapdoc_parameter_names.js +149 -0
  15. package/build/src/rules/cds_check_syntax.js +4 -4
  16. package/build/src/rules/change_if_to_case.js +3 -2
  17. package/build/src/rules/changing_sorted_line.js +235 -0
  18. package/build/src/rules/class_attribute_names.js +15 -6
  19. package/build/src/rules/delete_index_in_loop.js +163 -0
  20. package/build/src/rules/final_newline.js +78 -0
  21. package/build/src/rules/forbidden_identifier.js +4 -3
  22. package/build/src/rules/forbidden_void_type.js +4 -9
  23. package/build/src/rules/index.js +11 -0
  24. package/build/src/rules/inline_packed_computation.js +220 -0
  25. package/build/src/rules/intf_referencing_clas.js +3 -1
  26. package/build/src/rules/line_only_punc.js +1 -1
  27. package/build/src/rules/local_class_naming.js +15 -2
  28. package/build/src/rules/local_variable_names.js +18 -9
  29. package/build/src/rules/macro_naming.js +3 -2
  30. package/build/src/rules/method_parameter_names.js +17 -7
  31. package/build/src/rules/modify_only_own_db_tables.js +3 -2
  32. package/build/src/rules/no_exclamation_escape.js +32 -2
  33. package/build/src/rules/no_prefixes.js +25 -12
  34. package/build/src/rules/object_naming.js +18 -3
  35. package/build/src/rules/prefer_inline_cast.js +276 -0
  36. package/build/src/rules/range_row_values.js +200 -0
  37. package/build/src/rules/selection_screen_naming.js +21 -2
  38. package/build/src/rules/sicf_consistency.js +1 -2
  39. package/build/src/rules/sort_empty_key.js +188 -0
  40. package/build/src/rules/subrc_after_assign.js +220 -0
  41. package/build/src/rules/types_naming.js +3 -2
  42. package/build/src/rules/wrong_abapdoc_position.js +58 -11
  43. package/build/src/rules/xml_consistency.js +6 -2
  44. package/build/src/utils/name_validator.js +7 -3
  45. package/package.json +1 -1
@@ -1723,6 +1723,8 @@ declare class DataControl extends AbstractObject {
1723
1723
  declare class DataDefinition extends AbstractObject {
1724
1724
  private parserError;
1725
1725
  private parsedData;
1726
+ private typeCache;
1727
+ private typeCacheData;
1726
1728
  getType(): string;
1727
1729
  getAllowedNaming(): {
1728
1730
  maxLength: number;
@@ -2036,7 +2038,8 @@ declare class Domain extends AbstractObject {
2036
2038
  };
2037
2039
  getIdentifier(): Identifier | undefined;
2038
2040
  setDirty(): void;
2039
- parseType(reg: IRegistry, dataElement?: string, description?: string): AbstractType;
2041
+ parseType(reg: IRegistry): AbstractType;
2042
+ parseDomainType(reg: IRegistry, dataElement?: string, description?: string): AbstractType;
2040
2043
  parse(): {
2041
2044
  updated: boolean;
2042
2045
  runtime: number;
@@ -4770,6 +4773,7 @@ declare class MethodDefinition extends Identifier implements IMethodDefinition {
4770
4773
  private readonly exceptions;
4771
4774
  private readonly className;
4772
4775
  constructor(node: StatementNode, visibility: Visibility, input: SyntaxInput);
4776
+ private checkRaisingParameter;
4773
4777
  getVisibility(): Visibility;
4774
4778
  getClassName(): string;
4775
4779
  isRedefinition(): boolean;
@@ -4860,6 +4864,7 @@ declare class MethodParameters_2 implements IMethodParameters {
4860
4864
  private checkNameLengths;
4861
4865
  private workaroundRAP;
4862
4866
  private add;
4867
+ private checkKeywordNames;
4863
4868
  private isPassByValue;
4864
4869
  }
4865
4870
 
@@ -58,6 +58,9 @@ const Tokens = __importStar(require("../1_lexer/tokens"));
58
58
  const nodes_1 = require("../nodes");
59
59
  const version_1 = require("../../version");
60
60
  const result_1 = require("./result");
61
+ // shared result for "nothing matched", frozen so accidental mutation throws instead of leaking between calls.
62
+ // Returned arrays are never mutated by callers, which allows returning shared/input arrays as is
63
+ const EMPTY = Object.freeze([]);
61
64
  class Regex {
62
65
  constructor(r) {
63
66
  this.regexp = r;
@@ -69,17 +72,23 @@ class Regex {
69
72
  return [];
70
73
  }
71
74
  run(r) {
72
- const result = [];
75
+ let result = undefined;
73
76
  for (const input of r) {
74
77
  if (input.remainingLength() === 0) {
75
78
  continue;
76
79
  }
77
80
  const token = input.peek();
78
81
  if (this.regexp.test(token.getStr()) === true) {
79
- result.push(input.shift(new nodes_1.TokenNodeRegex(token)));
82
+ const shifted = input.shift(new nodes_1.TokenNodeRegex(token));
83
+ if (result === undefined) {
84
+ result = [shifted];
85
+ }
86
+ else {
87
+ result.push(shifted);
88
+ }
80
89
  }
81
90
  }
82
- return result;
91
+ return result !== null && result !== void 0 ? result : EMPTY;
83
92
  }
84
93
  railroad() {
85
94
  return "Railroad.Terminal(\"" + this.regexp.source.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\")";
@@ -102,15 +111,20 @@ class Word {
102
111
  return [];
103
112
  }
104
113
  run(r) {
105
- const result = [];
114
+ let result = undefined;
106
115
  for (const input of r) {
107
116
  if (input.remainingLength() !== 0
108
117
  && input.peek().getUpperStr() === this.s) {
109
- // console.log("match, " + this.s + result.length);
110
- result.push(input.shift(new nodes_1.TokenNode(input.peek())));
118
+ const shifted = input.shift(new nodes_1.TokenNode(input.peek()));
119
+ if (result === undefined) {
120
+ result = [shifted];
121
+ }
122
+ else {
123
+ result.push(shifted);
124
+ }
111
125
  }
112
126
  }
113
- return result;
127
+ return result !== null && result !== void 0 ? result : EMPTY;
114
128
  }
115
129
  railroad() {
116
130
  return "Railroad.Terminal('\"" + this.s + "\"')";
@@ -134,14 +148,20 @@ class Token {
134
148
  return [];
135
149
  }
136
150
  run(r) {
137
- const result = [];
151
+ let result = undefined;
138
152
  for (const input of r) {
139
153
  if (input.remainingLength() !== 0
140
154
  && input.peek().constructor === this.tokenType) {
141
- result.push(input.shift(new nodes_1.TokenNode(input.peek())));
155
+ const shifted = input.shift(new nodes_1.TokenNode(input.peek()));
156
+ if (result === undefined) {
157
+ result = [shifted];
158
+ }
159
+ else {
160
+ result.push(shifted);
161
+ }
142
162
  }
143
163
  }
144
- return result;
164
+ return result !== null && result !== void 0 ? result : EMPTY;
145
165
  }
146
166
  railroad() {
147
167
  let text = this.name;
@@ -179,9 +199,9 @@ class Vers {
179
199
  if (this.also === AlsoIn.OpenABAP) {
180
200
  return this.runnable.run(r);
181
201
  }
182
- return (0, version_1.releaseAtLeast)(version_1.Release.v702, this.release) ? this.runnable.run(r) : [];
202
+ return (0, version_1.releaseAtLeast)(version_1.Release.v702, this.release) ? this.runnable.run(r) : EMPTY;
183
203
  }
184
- return (0, version_1.releaseAtLeast)(Combi.getRelease(), this.release) ? this.runnable.run(r) : [];
204
+ return (0, version_1.releaseAtLeast)(Combi.getRelease(), this.release) ? this.runnable.run(r) : EMPTY;
185
205
  }
186
206
  getUsing() {
187
207
  return this.runnable.getUsing();
@@ -229,7 +249,7 @@ class LangVers {
229
249
  return this.runnable.run(r);
230
250
  }
231
251
  else {
232
- return [];
252
+ return EMPTY;
233
253
  }
234
254
  }
235
255
  railroad() {
@@ -262,7 +282,7 @@ class LangVersNot {
262
282
  return this.runnable.run(r);
263
283
  }
264
284
  else {
265
- return [];
285
+ return EMPTY;
266
286
  }
267
287
  }
268
288
  railroad() {
@@ -290,6 +310,22 @@ class OptionalPriority {
290
310
  return this.optional.getUsing();
291
311
  }
292
312
  run(r) {
313
+ if (r.length === 1) {
314
+ // single input, pass and return the input array without wrapping
315
+ const res = this.optional.run(r);
316
+ if (res.length > 1) {
317
+ return res;
318
+ }
319
+ else if (res.length === 0) {
320
+ return r;
321
+ }
322
+ else if (res[0].remainingLength() < r[0].remainingLength()) {
323
+ return res;
324
+ }
325
+ else {
326
+ return r;
327
+ }
328
+ }
293
329
  const result = [];
294
330
  for (const input of r) {
295
331
  const res = this.optional.run([input]);
@@ -329,6 +365,11 @@ class Optional {
329
365
  return this.optional.getUsing();
330
366
  }
331
367
  run(r) {
368
+ if (r.length === 1) {
369
+ // single input, pass and return the input array without wrapping
370
+ const res = this.optional.run(r);
371
+ return res.length === 0 ? r : r.concat(res);
372
+ }
332
373
  const result = [];
333
374
  for (const input of r) {
334
375
  result.push(input);
@@ -366,14 +407,16 @@ class Star {
366
407
  let result = r;
367
408
  try {
368
409
  let res = r;
369
- let input = [];
370
410
  for (;;) {
371
- input = res;
372
- res = this.sta.run(input);
411
+ res = this.sta.run(res);
373
412
  if (res.length === 0) {
374
413
  break;
375
414
  }
376
- if (res.length > 1000) {
415
+ if (result === r) {
416
+ // copy on first match, the input array must not be mutated
417
+ result = r.concat(res);
418
+ }
419
+ else if (res.length > 1000) {
377
420
  // avoid stack overflow
378
421
  result = result.concat(res);
379
422
  }
@@ -515,6 +558,17 @@ class Sequence {
515
558
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
516
559
  }
517
560
  run(r) {
561
+ if (r.length === 1) {
562
+ // single input, pass it down without wrapping and return the last result as is
563
+ let temp = r;
564
+ for (const sequence of this.list) {
565
+ temp = sequence.run(temp);
566
+ if (temp.length === 0) {
567
+ return EMPTY;
568
+ }
569
+ }
570
+ return temp;
571
+ }
518
572
  let result = [];
519
573
  for (const input of r) {
520
574
  let temp = [input];
@@ -592,12 +646,33 @@ class Expression {
592
646
  this.runnable = undefined;
593
647
  }
594
648
  run(r) {
595
- const results = [];
596
649
  if (this.runnable === undefined) {
597
650
  this.runnable = this.getRunnable();
598
651
  }
652
+ if (r.length === 1) {
653
+ // single input, pass it down without wrapping
654
+ const input = r[0];
655
+ const temp = this.runnable.run(r);
656
+ if (temp.length === 0) {
657
+ return EMPTY;
658
+ }
659
+ const results = new Array(temp.length);
660
+ for (let i = 0; i < temp.length; i++) {
661
+ const t = temp[i];
662
+ const consumed = input.remainingLength() - t.remainingLength();
663
+ results[i] = consumed > 0 ? t.wrapConsumed(consumed, new nodes_1.ExpressionNode(this)) : t;
664
+ }
665
+ return results;
666
+ }
667
+ let results = undefined;
599
668
  for (const input of r) {
600
669
  const temp = this.runnable.run([input]);
670
+ if (temp.length === 0) {
671
+ continue;
672
+ }
673
+ else if (results === undefined) {
674
+ results = [];
675
+ }
601
676
  for (const t of temp) {
602
677
  const consumed = input.remainingLength() - t.remainingLength();
603
678
  if (consumed > 0) {
@@ -609,8 +684,7 @@ class Expression {
609
684
  }
610
685
  }
611
686
  }
612
- // console.dir(results);
613
- return results;
687
+ return results !== null && results !== void 0 ? results : EMPTY;
614
688
  }
615
689
  listKeywords() {
616
690
  // do not recurse, all Expressions are evaluated only on first level
@@ -651,12 +725,16 @@ class Permutation {
651
725
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
652
726
  }
653
727
  run(r) {
654
- const result = [];
655
- const copy = this.list.slice();
728
+ let result = undefined;
729
+ let copy = undefined;
656
730
  for (let index = 0; index < this.list.length; index++) {
657
731
  const temp = this.list[index].run(r);
658
732
  if (temp.length !== 0) {
659
733
  // match
734
+ if (result === undefined || copy === undefined) {
735
+ result = [];
736
+ copy = this.list.slice();
737
+ }
660
738
  result.push(...temp);
661
739
  const left = copy;
662
740
  left.splice(index, 1);
@@ -668,7 +746,7 @@ class Permutation {
668
746
  }
669
747
  }
670
748
  }
671
- return result;
749
+ return result !== null && result !== void 0 ? result : EMPTY;
672
750
  }
673
751
  railroad() {
674
752
  const children = this.list.map((e) => { return e.railroad(); });
@@ -745,17 +823,31 @@ class Alternative {
745
823
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
746
824
  }
747
825
  run(r) {
748
- const result = [];
826
+ var _a;
827
+ // only allocate a new array when more than one alternative matches
828
+ let single = undefined;
829
+ let result = undefined;
749
830
  for (const sequ of this.list) {
750
831
  const temp = sequ.run(r);
751
- if (temp.length === 1) {
752
- result.push(temp[0]);
832
+ if (temp.length === 0) {
833
+ continue;
834
+ }
835
+ else if (result !== undefined) {
836
+ if (temp.length === 1) {
837
+ result.push(temp[0]);
838
+ }
839
+ else {
840
+ result.push(...temp);
841
+ }
842
+ }
843
+ else if (single !== undefined) {
844
+ result = single.concat(temp);
753
845
  }
754
846
  else {
755
- result.push(...temp);
847
+ single = temp;
756
848
  }
757
849
  }
758
- return result;
850
+ return (_a = result !== null && result !== void 0 ? result : single) !== null && _a !== void 0 ? _a : EMPTY;
759
851
  }
760
852
  railroad() {
761
853
  const children = this.list.map((e) => { return e.railroad(); });
@@ -806,21 +898,13 @@ class AlternativePriority {
806
898
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
807
899
  }
808
900
  run(r) {
809
- const result = [];
810
901
  for (const sequ of this.list) {
811
- // console.log(seq.toStr());
812
902
  const temp = sequ.run(r);
813
903
  if (temp.length > 0) {
814
- if (temp.length === 1) {
815
- result.push(temp[0]);
816
- }
817
- else {
818
- result.push(...temp);
819
- }
820
- break;
904
+ return temp;
821
905
  }
822
906
  }
823
- return result;
907
+ return EMPTY;
824
908
  }
825
909
  railroad() {
826
910
  const children = this.list.map((e) => { return e.railroad(); });
@@ -1026,18 +1110,21 @@ class StopBefore2 {
1026
1110
  getUsing() { return []; }
1027
1111
  run(r) {
1028
1112
  var _a;
1029
- const result = [];
1030
- for (const input of r) {
1113
+ // only copy when something is filtered out
1114
+ let result = undefined;
1115
+ for (let i = 0; i < r.length; i++) {
1116
+ const input = r[i];
1031
1117
  const next = input.peek();
1032
- if (next === undefined) {
1033
- continue;
1034
- }
1035
- if (next.getUpperStr() === this.t1 && ((_a = input.peekAt(1)) === null || _a === void 0 ? void 0 : _a.getUpperStr()) === this.t2) {
1118
+ if (next === undefined
1119
+ || (next.getUpperStr() === this.t1 && ((_a = input.peekAt(1)) === null || _a === void 0 ? void 0 : _a.getUpperStr()) === this.t2)) {
1120
+ if (result === undefined) {
1121
+ result = r.slice(0, i);
1122
+ }
1036
1123
  continue;
1037
1124
  }
1038
- result.push(input);
1125
+ result === null || result === void 0 ? void 0 : result.push(input);
1039
1126
  }
1040
- return result;
1127
+ return result !== null && result !== void 0 ? result : r;
1041
1128
  }
1042
1129
  railroad() { return "Railroad.Terminal('stopBefore(" + this.t1 + " " + this.t2 + ")')"; }
1043
1130
  toStr() { return "stopBefore(" + this.t1 + "," + this.t2 + ")"; }
@@ -1052,15 +1139,20 @@ class StopBefore1 {
1052
1139
  getUsing() { return []; }
1053
1140
  run(r) {
1054
1141
  var _a;
1055
- const result = [];
1056
- for (const input of r) {
1142
+ // only copy when something is filtered out
1143
+ let result = undefined;
1144
+ for (let i = 0; i < r.length; i++) {
1145
+ const input = r[i];
1057
1146
  const next = (_a = input.peek()) === null || _a === void 0 ? void 0 : _a.getUpperStr();
1058
1147
  if (next !== undefined && this.words.includes(next)) {
1148
+ if (result === undefined) {
1149
+ result = r.slice(0, i);
1150
+ }
1059
1151
  continue;
1060
1152
  }
1061
- result.push(input);
1153
+ result === null || result === void 0 ? void 0 : result.push(input);
1062
1154
  }
1063
- return result;
1155
+ return result !== null && result !== void 0 ? result : r;
1064
1156
  }
1065
1157
  railroad() { return "Railroad.Terminal('stopBefore(" + this.words.join("|") + ")')"; }
1066
1158
  toStr() { return "stopBefore(" + this.words.join(",") + ")"; }
@@ -5,7 +5,9 @@ const combi_1 = require("../combi");
5
5
  const _1 = require(".");
6
6
  class MethodParamOptional extends combi_1.Expression {
7
7
  getRunnable() {
8
- return (0, combi_1.seq)(_1.MethodParam, (0, combi_1.optPrio)("OPTIONAL"));
8
+ // not optPrio, a parameter named "optional" can follow one with a DEFAULT value:
9
+ // "a TYPE i DEFAULT 5 optional TYPE i"
10
+ return (0, combi_1.seq)(_1.MethodParam, (0, combi_1.opt)("OPTIONAL"));
9
11
  }
10
12
  }
11
13
  exports.MethodParamOptional = MethodParamOptional;
@@ -42,6 +42,7 @@ const Types = __importStar(require("../types/basic"));
42
42
  const _scope_type_1 = require("./_scope_type");
43
43
  const _object_oriented_1 = require("./_object_oriented");
44
44
  const class_constant_1 = require("../types/class_constant");
45
+ const class_attribute_1 = require("../types/class_attribute");
45
46
  const identifier_1 = require("../1_lexer/tokens/identifier");
46
47
  const _reference_1 = require("./_reference");
47
48
  const basic_1 = require("../types/basic");
@@ -892,15 +893,18 @@ class BasicTypes {
892
893
  const firstName = firstToken.getStr();
893
894
  if (firstNode.get() instanceof Expressions.Field) {
894
895
  const found = this.input.scope.findVariable(firstName);
895
- const val = found === null || found === void 0 ? void 0 : found.getValue();
896
- if (typeof val === "string") {
897
- this.input.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.input.filename);
898
- return val;
896
+ if (found === undefined) {
897
+ const message = `"${firstName}" not found, findTop`;
898
+ this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, firstToken, message));
899
+ return undefined;
899
900
  }
900
- else if ((found === null || found === void 0 ? void 0 : found.getType()) instanceof basic_1.StructureType) {
901
- this.input.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.input.filename);
901
+ this.input.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.input.filename);
902
+ if (this.isConstant(found) === false) {
903
+ const message = `VALUE, ${expr.concatTokens().toLowerCase()} is not a constant`;
904
+ this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, firstToken, message));
905
+ return undefined;
902
906
  }
903
- return undefined;
907
+ return this.constantValue(expr, found.getValue());
904
908
  }
905
909
  else if (firstNode.get() instanceof Expressions.ClassName
906
910
  && firstName.toLowerCase() === this.input.scope.getName().toLowerCase()
@@ -909,12 +913,18 @@ class BasicTypes {
909
913
  const children = expr.getChildren();
910
914
  const token = (_a = children[2]) === null || _a === void 0 ? void 0 : _a.getFirstToken();
911
915
  const found = this.input.scope.findVariable(token.getStr());
912
- const val = found === null || found === void 0 ? void 0 : found.getValue();
913
- if (typeof val === "string") {
914
- this.input.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.input.filename);
915
- return val;
916
+ if (found === undefined) {
917
+ const message = `"${token.getStr()}" not found, findTop`;
918
+ this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, token, message));
919
+ return undefined;
916
920
  }
917
- return undefined;
921
+ this.input.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.input.filename);
922
+ if (this.isConstant(found) === false) {
923
+ const message = `VALUE, ${expr.concatTokens().toLowerCase()} is not a constant`;
924
+ this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, token, message));
925
+ return undefined;
926
+ }
927
+ return this.constantValue(expr, found.getValue());
918
928
  }
919
929
  else if (firstNode.get() instanceof Expressions.ClassName) {
920
930
  const obj = this.input.scope.findObjectDefinition(firstName);
@@ -937,24 +947,58 @@ class BasicTypes {
937
947
  if (c instanceof class_constant_1.ClassConstant) {
938
948
  this.input.scope.addReference(firstToken, obj, _reference_1.ReferenceType.ObjectOrientedReference, this.input.filename, { ooName: obj.getName() });
939
949
  this.input.scope.addReference(token, c, _reference_1.ReferenceType.DataReadReference, this.input.filename);
940
- const val = c.getValue();
941
- if (typeof val === "string") {
942
- return val;
943
- }
944
- else if (typeof val === "object" && children[4]) {
945
- const name = children[4].getFirstToken().getStr();
946
- if (val[name] !== undefined) {
947
- return val[name];
948
- }
949
- }
950
+ return this.constantValue(expr, c.getValue());
951
+ }
952
+ const helper = new _object_oriented_1.ObjectOriented(this.input.scope);
953
+ const attribute = helper.searchAttributeName(obj, attr);
954
+ if (attribute) {
955
+ this.input.scope.addReference(firstToken, obj, _reference_1.ReferenceType.ObjectOrientedReference, this.input.filename, { ooName: obj.getName() });
956
+ this.input.scope.addReference(token, attribute, _reference_1.ReferenceType.DataReadReference, this.input.filename);
957
+ const message = `VALUE, ${expr.concatTokens().toLowerCase()} is not a constant`;
958
+ this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, token, message));
950
959
  return undefined;
951
960
  }
952
- throw new Error("resolveConstantValue, constant not found " + attr);
961
+ const message = `Attribute or constant "${attr}" not found in "${obj.getName()}"`;
962
+ this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, token, message));
963
+ return undefined;
953
964
  }
954
965
  else {
955
966
  throw new Error("resolveConstantValue, unexpected structure");
956
967
  }
957
968
  }
969
+ isConstant(identifier) {
970
+ if (identifier instanceof class_attribute_1.ClassAttribute) {
971
+ return false;
972
+ }
973
+ const meta = identifier.getMeta();
974
+ if (meta.includes("read_only" /* IdentifierMeta.ReadOnly */) === false) {
975
+ return false;
976
+ }
977
+ if (meta.includes("static" /* IdentifierMeta.Static */)) {
978
+ return true;
979
+ }
980
+ // Built-in constants and built-in system fields share ReadOnly/BuiltIn metadata.
981
+ // Only the constants have a value; system fields such as SY-INDEX do not.
982
+ return meta.includes("built-in" /* IdentifierMeta.BuiltIn */) && identifier.getValue() !== undefined;
983
+ }
984
+ constantValue(expr, value) {
985
+ if (typeof value === "string") {
986
+ return value;
987
+ }
988
+ else if (typeof value === "object" && value !== null) {
989
+ let current = value;
990
+ for (const child of expr.getChildren().slice(1)) {
991
+ if (child instanceof nodes_1.ExpressionNode && child.get() instanceof Expressions.ComponentName) {
992
+ if (typeof current !== "object" || current === null) {
993
+ return undefined;
994
+ }
995
+ current = current[child.getFirstToken().getStr()];
996
+ }
997
+ }
998
+ return typeof current === "string" ? current : undefined;
999
+ }
1000
+ return undefined;
1001
+ }
958
1002
  resolveTypeRef(chain) {
959
1003
  var _a;
960
1004
  if (chain === undefined) {
@@ -50,6 +50,12 @@ class Append {
50
50
  if (target) {
51
51
  targetType = target_1.Target.runSyntax(target, input);
52
52
  }
53
+ // a hashed table has no index, APPEND adds at the end
54
+ if (targetType instanceof basic_1.TableType && targetType.getAccessType() === basic_1.TableAccessType.hashed) {
55
+ const message = "Implicit or explicit index operation on hashed table is not possible";
56
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
57
+ return;
58
+ }
53
59
  const fsTarget = node.findExpressionAfterToken("ASSIGNING");
54
60
  if (fsTarget && fsTarget.get() instanceof Expressions.FSTarget) {
55
61
  if (!(targetType instanceof basic_1.TableType) && !(targetType instanceof basic_1.VoidType) && !(targetType instanceof basic_1.UnknownType)) {
@@ -39,6 +39,7 @@ const Expressions = __importStar(require("../2_statements/expressions"));
39
39
  const method_parameters_1 = require("./method_parameters");
40
40
  const _identifier_1 = require("../4_file_information/_identifier");
41
41
  const _reference_1 = require("../5_syntax/_reference");
42
+ const _syntax_input_1 = require("../5_syntax/_syntax_input");
42
43
  class MethodDefinition extends _identifier_1.Identifier {
43
44
  // todo: final flag
44
45
  constructor(node, visibility, input) {
@@ -80,6 +81,7 @@ class MethodDefinition extends _identifier_1.Identifier {
80
81
  this.static = true;
81
82
  }
82
83
  this.raising = [];
84
+ this.checkRaisingParameter(node, input);
83
85
  for (const r of ((_c = node.findDirectExpression(Expressions.MethodDefRaising)) === null || _c === void 0 ? void 0 : _c.findAllExpressions(Expressions.ClassName)) || []) {
84
86
  const token = r.getFirstToken();
85
87
  const name = token.getStr();
@@ -104,6 +106,26 @@ class MethodDefinition extends _identifier_1.Identifier {
104
106
  this.visibility = visibility;
105
107
  this.parameters = new method_parameters_1.MethodParameters(node, input, this.abstract);
106
108
  }
109
+ // A system reads a parameter named RAISING as the RAISING addition, measured on 758:
110
+ // "IMPORTING a TYPE i raising TYPE i" fails with 'Type "TYPE" is unknown'
111
+ checkRaisingParameter(node, input) {
112
+ const raising = node.findDirectExpression(Expressions.MethodDefRaising);
113
+ const first = raising === null || raising === void 0 ? void 0 : raising.getChildren()[1];
114
+ if (raising === undefined
115
+ || first === undefined
116
+ || !(first.get() instanceof Expressions.ClassName)
117
+ || ["TYPE", "LIKE"].includes(first.getFirstToken().getStr().toUpperCase()) === false) {
118
+ return;
119
+ }
120
+ if (node.findDirectExpression(Expressions.MethodDefImporting) === undefined
121
+ && node.findDirectExpression(Expressions.MethodDefExporting) === undefined
122
+ && node.findDirectExpression(Expressions.MethodDefChanging) === undefined) {
123
+ return;
124
+ }
125
+ const token = raising.getFirstToken();
126
+ const message = "Parameter \"" + token.getStr() + "\" is read as the RAISING addition, rename it or escape it as !" + token.getStr();
127
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
128
+ }
107
129
  getVisibility() {
108
130
  return this.visibility;
109
131
  }