@abaplint/core 2.119.59 → 2.119.61

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.
@@ -4405,6 +4405,10 @@ declare interface ISyntaxSettings {
4405
4405
  * @uniqueItems true
4406
4406
  */
4407
4407
  globalConstants?: string[];
4408
+ /** List of names to void in ambigious statements (regex not possible)
4409
+ * @uniqueItems true
4410
+ */
4411
+ ambigiousVoids?: string[];
4408
4412
  /** List of full named global macros (regex not possible)
4409
4413
  * @uniqueItems true
4410
4414
  */
@@ -6403,10 +6407,13 @@ declare class Result {
6403
6407
  private readonly tokens;
6404
6408
  private readonly tokenIndex;
6405
6409
  private nodes;
6410
+ private nodeCount;
6406
6411
  constructor(tokens: readonly Token[], tokenIndex: number, nodes?: (ExpressionNode | TokenNode)[]);
6412
+ private static fromChain;
6407
6413
  peek(): Token;
6408
6414
  peekAt(offset: number): Token | undefined;
6409
6415
  shift(node: ExpressionNode | TokenNode): Result;
6416
+ wrapConsumed(consumedTokens: number, node: ExpressionNode): Result;
6410
6417
  popNode(): ExpressionNode | TokenNode | undefined;
6411
6418
  getNodes(): (ExpressionNode | TokenNode)[];
6412
6419
  setNodes(n: (ExpressionNode | TokenNode)[]): void;
@@ -12,6 +12,37 @@ const ModeStr = 3;
12
12
  const ModeTemplate = 4;
13
13
  const ModeComment = 5;
14
14
  const ModePragma = 6;
15
+ // character codes, used for integer comparisons in the hot loop
16
+ const EOF = -1; // no character (start/end of file)
17
+ const CH_TAB = 9; // "\t"
18
+ const CH_NL = 10; // "\n"
19
+ const CH_SPACE = 32; // " "
20
+ const CH_DQUOTE = 34; // "\""
21
+ const CH_HASH = 35; // "#"
22
+ const CH_QUOTE = 39; // "'"
23
+ const CH_STAR = 42; // "*"
24
+ const CH_DASH = 45; // "-"
25
+ const CH_COMMA = 44; // ","
26
+ const CH_DOT = 46; // "."
27
+ const CH_COLON = 58; // ":"
28
+ const CH_EQUALS = 61; // "="
29
+ const CH_GT = 62; // ">"
30
+ const CH_AT = 64; // "@"
31
+ const CH_BACKSLASH = 92; // "\\"
32
+ const CH_BACKTICK = 96; // "`"
33
+ const CH_LBRACE = 123; // "{"
34
+ const CH_PIPE = 124; // "|"
35
+ const CH_RBRACE = 125; // "}"
36
+ // characters that terminate the current token
37
+ const SPLITS = new Set([
38
+ CH_SPACE, CH_COLON, CH_DOT, CH_COMMA, CH_DASH, 43 /* + */, 40 /* ( */,
39
+ 41 /* ) */, 91 /* [ */, 93 /* ] */, CH_BACKSLASH, CH_TAB, CH_NL
40
+ ]);
41
+ // single characters that are emitted as their own token
42
+ const BUFS = new Set([
43
+ CH_DOT, CH_COMMA, CH_COLON, 40 /* ( */, 41 /* ) */, 91 /* [ */,
44
+ 93 /* ] */, 43 /* + */, CH_AT
45
+ ]);
15
46
  class Lexer {
16
47
  run(file, virtual) {
17
48
  this.virtual = virtual;
@@ -26,15 +57,17 @@ class Lexer {
26
57
  const col = this.stream.getCol();
27
58
  const row = this.stream.getRow();
28
59
  let whiteBefore = false;
29
- if (this.stream.getOffset() - s.length >= 0) {
30
- const prev = this.stream.getRaw().substr(this.stream.getOffset() - s.length, 1);
31
- if (prev === " " || prev === "\n" || prev === "\t" || prev === ":") {
60
+ const beforeOffset = this.stream.getOffset() - s.length;
61
+ if (beforeOffset >= 0) {
62
+ const prev = this.stream.charCodeAt(beforeOffset);
63
+ if (prev === CH_SPACE || prev === CH_NL || prev === CH_TAB || prev === CH_COLON) {
32
64
  whiteBefore = true;
33
65
  }
34
66
  }
35
67
  let whiteAfter = false;
36
68
  const next = this.stream.nextChar();
37
- if (next === " " || next === "\n" || next === "\t" || next === ":" || next === "," || next === "." || next === "" || next === "\"") {
69
+ if (next === CH_SPACE || next === CH_NL || next === CH_TAB || next === CH_COLON
70
+ || next === CH_COMMA || next === CH_DOT || next === EOF || next === CH_DQUOTE) {
38
71
  whiteAfter = true;
39
72
  }
40
73
  let pos = new position_1.Position(row, col - s.length);
@@ -204,10 +237,10 @@ class Lexer {
204
237
  }
205
238
  }
206
239
  if (tok === undefined && this.m === ModeNormal && s.charAt(0) === "\\") {
207
- const adj = this.stream.nextChar() === "" ? 1 : 0;
240
+ const adj = this.stream.nextChar() === EOF ? 1 : 0;
208
241
  const prevOffset = this.stream.getOffset() - s.length - adj;
209
- const prevChar = prevOffset >= 0 ? this.stream.getRaw().substr(prevOffset, 1) : "";
210
- const whiteBeforeBackslash = prevChar === " " || prevChar === "\n" || prevChar === "\t" || prevChar === ":";
242
+ const prevChar = this.stream.charCodeAt(prevOffset);
243
+ const whiteBeforeBackslash = prevChar === CH_SPACE || prevChar === CH_NL || prevChar === CH_TAB || prevChar === CH_COLON;
211
244
  if (!whiteBeforeBackslash) {
212
245
  tok = new tokens_1.AssociationName(pos, s);
213
246
  }
@@ -220,100 +253,77 @@ class Lexer {
220
253
  this.buffer.clear();
221
254
  }
222
255
  process(raw) {
223
- this.stream = new lexer_stream_1.LexerStream(raw.replace(/\r/g, ""));
224
- this.buffer = new lexer_buffer_1.LexerBuffer();
225
- const splits = {};
226
- splits[" "] = true;
227
- splits[":"] = true;
228
- splits["."] = true;
229
- splits[","] = true;
230
- splits["-"] = true;
231
- splits["+"] = true;
232
- splits["("] = true;
233
- splits[")"] = true;
234
- splits["["] = true;
235
- splits["]"] = true;
236
- splits["\\"] = true;
237
- splits["\t"] = true;
238
- splits["\n"] = true;
239
- const bufs = {};
240
- bufs["."] = true;
241
- bufs[","] = true;
242
- bufs[":"] = true;
243
- bufs["("] = true;
244
- bufs[")"] = true;
245
- bufs["["] = true;
246
- bufs["]"] = true;
247
- bufs["+"] = true;
248
- bufs["@"] = true;
256
+ const stream = new lexer_stream_1.LexerStream(raw.replace(/\r/g, ""));
257
+ this.stream = stream;
258
+ this.buffer = new lexer_buffer_1.LexerBuffer(stream.getRaw());
249
259
  for (;;) {
250
- const current = this.stream.currentChar();
251
- const buf = this.buffer.add(current);
252
- const ahead = this.stream.nextChar();
253
- const aahead = this.stream.nextNextChar();
260
+ const current = stream.currentChar();
261
+ this.buffer.add(stream.getOffset());
262
+ const ahead = stream.nextChar();
263
+ const aahead = stream.nextNextChar();
254
264
  if (this.m === ModeNormal) {
255
- if (splits[ahead]) {
265
+ if (SPLITS.has(ahead)) {
256
266
  this.add();
257
267
  }
258
- else if (ahead === "'") {
268
+ else if (ahead === CH_QUOTE) {
259
269
  // start string
260
270
  this.add();
261
271
  this.m = ModeStr;
262
272
  }
263
- else if (ahead === "|" || ahead === "}") {
273
+ else if (ahead === CH_PIPE || ahead === CH_RBRACE) {
264
274
  // start template
265
275
  this.add();
266
276
  this.m = ModeTemplate;
267
277
  }
268
- else if (ahead === "`") {
278
+ else if (ahead === CH_BACKTICK) {
269
279
  // start ping
270
280
  this.add();
271
281
  this.m = ModePing;
272
282
  }
273
- else if (aahead === "##") {
283
+ else if (ahead === CH_HASH && aahead === CH_HASH) {
274
284
  // start pragma
275
285
  this.add();
276
286
  this.m = ModePragma;
277
287
  }
278
- else if (ahead === "\""
279
- || (ahead === "*" && current === "\n")) {
288
+ else if (ahead === CH_DQUOTE
289
+ || (ahead === CH_STAR && current === CH_NL)) {
280
290
  // start comment
281
291
  this.add();
282
292
  this.m = ModeComment;
283
293
  }
284
- else if (ahead === "@" && buf.trim().length === 0) {
294
+ else if (ahead === CH_AT && this.buffer.get().trim().length === 0) {
285
295
  this.add();
286
296
  }
287
- else if (aahead === "->"
288
- || aahead === "=>") {
297
+ else if ((ahead === CH_DASH || ahead === CH_EQUALS) && aahead === CH_GT) {
289
298
  this.add();
290
299
  }
291
- else if (current === ">"
292
- && ahead !== " "
293
- && (this.stream.prevChar() === "-" || this.stream.prevChar() === "=")) {
300
+ else if (current === CH_GT
301
+ && ahead !== CH_SPACE
302
+ && (stream.prevChar() === CH_DASH || stream.prevChar() === CH_EQUALS)) {
294
303
  // arrows
295
304
  this.add();
296
305
  }
297
- else if (buf.length === 1
298
- && (bufs[buf]
299
- || (buf === "-" && ahead !== ">"))) {
306
+ else if (this.buffer.length() === 1
307
+ && (BUFS.has(current)
308
+ || (current === CH_DASH && ahead !== CH_GT))) {
300
309
  this.add();
301
310
  }
302
311
  }
303
- else if (this.m === ModePragma && (ahead === "," || ahead === ":" || ahead === "." || ahead === " " || ahead === "\n")) {
312
+ else if (this.m === ModePragma && (ahead === CH_COMMA || ahead === CH_COLON
313
+ || ahead === CH_DOT || ahead === CH_SPACE || ahead === CH_NL)) {
304
314
  // end of pragma
305
315
  this.add();
306
316
  this.m = ModeNormal;
307
317
  }
308
318
  else if (this.m === ModePing
309
- && buf.length > 1
310
- && current === "`"
311
- && aahead !== "``"
312
- && ahead !== "`"
313
- && this.buffer.countIsEven("`")) {
319
+ && this.buffer.length() > 1
320
+ && current === CH_BACKTICK
321
+ && !(ahead === CH_BACKTICK && aahead === CH_BACKTICK)
322
+ && ahead !== CH_BACKTICK
323
+ && this.buffer.countIsEven(CH_BACKTICK)) {
314
324
  // end of ping
315
325
  this.add();
316
- if (ahead === `"`) {
326
+ if (ahead === CH_DQUOTE) {
317
327
  this.m = ModeComment;
318
328
  }
319
329
  else {
@@ -321,41 +331,41 @@ class Lexer {
321
331
  }
322
332
  }
323
333
  else if (this.m === ModeTemplate
324
- && buf.length > 1
325
- && (current === "|" || current === "{")
326
- && (this.stream.prevChar() !== "\\" || this.stream.prevPrevChar() === "\\\\")) {
334
+ && this.buffer.length() > 1
335
+ && (current === CH_PIPE || current === CH_LBRACE)
336
+ && (stream.prevChar() !== CH_BACKSLASH || (stream.prevPrevChar() === CH_BACKSLASH && stream.prevChar() === CH_BACKSLASH))) {
327
337
  // end of template
328
338
  this.add();
329
339
  this.m = ModeNormal;
330
340
  }
331
341
  else if (this.m === ModeTemplate
332
- && ahead === "}"
333
- && current !== "\\") {
342
+ && ahead === CH_RBRACE
343
+ && current !== CH_BACKSLASH) {
334
344
  this.add();
335
345
  }
336
346
  else if (this.m === ModeStr
337
- && current === "'"
338
- && buf.length > 1
339
- && aahead !== "''"
340
- && ahead !== "'"
341
- && this.buffer.countIsEven("'")) {
347
+ && current === CH_QUOTE
348
+ && this.buffer.length() > 1
349
+ && !(ahead === CH_QUOTE && aahead === CH_QUOTE)
350
+ && ahead !== CH_QUOTE
351
+ && this.buffer.countIsEven(CH_QUOTE)) {
342
352
  // end of string
343
353
  this.add();
344
- if (ahead === "\"") {
354
+ if (ahead === CH_DQUOTE) {
345
355
  this.m = ModeComment;
346
356
  }
347
357
  else {
348
358
  this.m = ModeNormal;
349
359
  }
350
360
  }
351
- else if (ahead === "\n" && this.m !== ModeTemplate) {
361
+ else if (ahead === CH_NL && this.m !== ModeTemplate) {
352
362
  this.add();
353
363
  this.m = ModeNormal;
354
364
  }
355
- else if (this.m === ModeTemplate && current === "\n") {
365
+ else if (this.m === ModeTemplate && current === CH_NL) {
356
366
  this.add();
357
367
  }
358
- if (!this.stream.advance()) {
368
+ if (!stream.advance()) {
359
369
  break;
360
370
  }
361
371
  }
@@ -1,24 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LexerBuffer = void 0;
4
+ // The buffer holds a reference to the raw input and tracks the [start, end)
5
+ // offset range of the current token, so the token string can be sliced out with
6
+ // a single substring() instead of being concatenated one character at a time.
4
7
  class LexerBuffer {
5
- constructor() {
6
- this.buf = "";
8
+ constructor(raw) {
9
+ this.raw = raw;
10
+ this.start = 0;
11
+ this.end = 0;
12
+ this.empty = true;
7
13
  }
8
- add(s) {
9
- this.buf = this.buf + s;
10
- return this.buf;
14
+ add(offset) {
15
+ if (this.empty === true) {
16
+ this.start = offset < 0 ? 0 : offset;
17
+ this.empty = false;
18
+ }
19
+ this.end = offset + 1;
11
20
  }
12
21
  get() {
13
- return this.buf;
22
+ return this.raw.substring(this.start, this.end);
23
+ }
24
+ length() {
25
+ return this.end - this.start;
14
26
  }
15
27
  clear() {
16
- this.buf = "";
28
+ this.start = 0;
29
+ this.end = 0;
30
+ this.empty = true;
17
31
  }
18
32
  countIsEven(char) {
19
33
  let count = 0;
20
- for (let i = 0; i < this.buf.length; i += 1) {
21
- if (this.buf.charAt(i) === char) {
34
+ for (let i = this.start; i < this.end; i += 1) {
35
+ if (this.raw.charCodeAt(i) === char) {
22
36
  count += 1;
23
37
  }
24
38
  }
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LexerStream = void 0;
4
+ const NL = 10; // "\n"
5
+ const EOF = -1; // no character (start/end of file)
4
6
  class LexerStream {
5
7
  constructor(raw) {
6
8
  this.offset = -1;
@@ -9,7 +11,7 @@ class LexerStream {
9
11
  this.col = 0;
10
12
  }
11
13
  advance() {
12
- if (this.currentChar() === "\n") {
14
+ if (this.currentChar() === NL) {
13
15
  this.col = 1;
14
16
  this.row = this.row + 1;
15
17
  }
@@ -27,38 +29,51 @@ class LexerStream {
27
29
  getRow() {
28
30
  return this.row;
29
31
  }
32
+ // the *Char() accessors return character codes (charCodeAt) rather than
33
+ // single character strings, to avoid allocating a string per input character
34
+ // in the lexer hot loop. EOF (-1) is returned when the offset is out of range.
30
35
  prevChar() {
31
- if (this.offset - 1 < 0) {
32
- return "";
36
+ const o = this.offset - 1;
37
+ if (o < 0) {
38
+ return EOF;
33
39
  }
34
- return this.raw.substr(this.offset - 1, 1);
40
+ return this.raw.charCodeAt(o);
35
41
  }
36
42
  prevPrevChar() {
37
- if (this.offset - 2 < 0) {
38
- return "";
43
+ const o = this.offset - 2;
44
+ if (o < 0) {
45
+ return EOF;
39
46
  }
40
- return this.raw.substr(this.offset - 2, 2);
47
+ return this.raw.charCodeAt(o);
41
48
  }
42
49
  currentChar() {
43
50
  if (this.offset < 0) {
44
- return "\n"; // simulate newline at start of file to handle star(*) comments
51
+ return NL; // simulate newline at start of file to handle star(*) comments
45
52
  }
46
53
  else if (this.offset >= this.raw.length) {
47
- return "";
54
+ return EOF;
48
55
  }
49
- return this.raw.substr(this.offset, 1);
56
+ return this.raw.charCodeAt(this.offset);
50
57
  }
51
58
  nextChar() {
52
- if (this.offset + 2 > this.raw.length) {
53
- return "";
59
+ const o = this.offset + 1;
60
+ if (o >= this.raw.length) {
61
+ return EOF;
54
62
  }
55
- return this.raw.substr(this.offset + 1, 1);
63
+ return this.raw.charCodeAt(o);
56
64
  }
57
65
  nextNextChar() {
58
- if (this.offset + 3 > this.raw.length) {
59
- return this.nextChar();
66
+ const o = this.offset + 2;
67
+ if (o >= this.raw.length) {
68
+ return EOF;
60
69
  }
61
- return this.raw.substr(this.offset + 1, 2);
70
+ return this.raw.charCodeAt(o);
71
+ }
72
+ charCodeAt(o) {
73
+ if (o < 0 || o >= this.raw.length) {
74
+ return EOF;
75
+ }
76
+ return this.raw.charCodeAt(o);
62
77
  }
63
78
  getRaw() {
64
79
  return this.raw;
@@ -123,8 +123,9 @@ class Word {
123
123
  }
124
124
  }
125
125
  class Token {
126
- constructor(s) {
127
- this.name = s;
126
+ constructor(t) {
127
+ this.tokenType = t;
128
+ this.name = t.name;
128
129
  }
129
130
  listKeywords() {
130
131
  return [];
@@ -136,7 +137,7 @@ class Token {
136
137
  const result = [];
137
138
  for (const input of r) {
138
139
  if (input.remainingLength() !== 0
139
- && input.peek().constructor.name === this.name) {
140
+ && input.peek().constructor === this.tokenType) {
140
141
  result.push(input.shift(new nodes_1.TokenNode(input.peek())));
141
142
  }
142
143
  }
@@ -332,7 +333,12 @@ class Optional {
332
333
  for (const input of r) {
333
334
  result.push(input);
334
335
  const res = this.optional.run([input]);
335
- result.push(...res);
336
+ if (res.length === 1) {
337
+ result.push(res[0]);
338
+ }
339
+ else {
340
+ result.push(...res);
341
+ }
336
342
  }
337
343
  return result;
338
344
  }
@@ -371,6 +377,9 @@ class Star {
371
377
  // avoid stack overflow
372
378
  result = result.concat(res);
373
379
  }
380
+ else if (res.length === 1) {
381
+ result.push(res[0]);
382
+ }
374
383
  else {
375
384
  result.push(...res);
376
385
  }
@@ -522,6 +531,9 @@ class Sequence {
522
531
  // avoid stack overflow
523
532
  result = result.concat(temp);
524
533
  }
534
+ else if (temp.length === 1) {
535
+ result.push(temp[0]);
536
+ }
525
537
  else {
526
538
  result.push(...temp);
527
539
  }
@@ -587,24 +599,14 @@ class Expression {
587
599
  for (const input of r) {
588
600
  const temp = this.runnable.run([input]);
589
601
  for (const t of temp) {
590
- let consumed = input.remainingLength() - t.remainingLength();
602
+ const consumed = input.remainingLength() - t.remainingLength();
591
603
  if (consumed > 0) {
592
- const originalLength = t.getNodes().length;
593
- const children = [];
594
- while (consumed > 0) {
595
- const sub = t.popNode();
596
- if (sub) {
597
- children.push(sub);
598
- consumed = consumed - sub.countTokens();
599
- }
600
- }
601
604
  const re = new nodes_1.ExpressionNode(this);
602
- re.setChildren(children.reverse());
603
- const n = t.getNodes().slice(0, originalLength - consumed);
604
- n.push(re);
605
- t.setNodes(n);
605
+ results.push(t.wrapConsumed(consumed, re));
606
+ }
607
+ else {
608
+ results.push(t);
606
609
  }
607
- results.push(t);
608
610
  }
609
611
  }
610
612
  // console.dir(results);
@@ -746,7 +748,12 @@ class Alternative {
746
748
  const result = [];
747
749
  for (const sequ of this.list) {
748
750
  const temp = sequ.run(r);
749
- result.push(...temp);
751
+ if (temp.length === 1) {
752
+ result.push(temp[0]);
753
+ }
754
+ else {
755
+ result.push(...temp);
756
+ }
750
757
  }
751
758
  return result;
752
759
  }
@@ -804,7 +811,12 @@ class AlternativePriority {
804
811
  // console.log(seq.toStr());
805
812
  const temp = sequ.run(r);
806
813
  if (temp.length > 0) {
807
- result.push(...temp);
814
+ if (temp.length === 1) {
815
+ result.push(temp[0]);
816
+ }
817
+ else {
818
+ result.push(...temp);
819
+ }
808
820
  break;
809
821
  }
810
822
  }
@@ -920,7 +932,7 @@ function regex(r) {
920
932
  return new Regex(r);
921
933
  }
922
934
  function tok(t) {
923
- return new Token(t.name);
935
+ return new Token(t);
924
936
  }
925
937
  const expressionSingletons = {};
926
938
  const stringSingletons = {};
@@ -7,11 +7,17 @@ class Result {
7
7
  // nodes: matched tokens
8
8
  this.tokens = tokens;
9
9
  this.tokenIndex = tokenIndex;
10
- this.nodes = nodes;
11
- if (this.nodes === undefined) {
12
- this.nodes = [];
10
+ this.nodeCount = 0;
11
+ if (nodes !== undefined) {
12
+ this.setNodes(nodes);
13
13
  }
14
14
  }
15
+ static fromChain(tokens, tokenIndex, nodes, nodeCount) {
16
+ const ret = new Result(tokens, tokenIndex);
17
+ ret.nodes = nodes;
18
+ ret.nodeCount = nodeCount;
19
+ return ret;
20
+ }
15
21
  peek() {
16
22
  return this.tokens[this.tokenIndex];
17
23
  }
@@ -19,18 +25,54 @@ class Result {
19
25
  return this.tokens[this.tokenIndex + offset];
20
26
  }
21
27
  shift(node) {
22
- const cp = this.nodes.slice();
23
- cp.push(node);
24
- return new Result(this.tokens, this.tokenIndex + 1, cp);
28
+ return Result.fromChain(this.tokens, this.tokenIndex + 1, { node, previous: this.nodes }, this.nodeCount + 1);
29
+ }
30
+ wrapConsumed(consumedTokens, node) {
31
+ let current = this.nodes;
32
+ let currentCount = this.nodeCount;
33
+ const children = [];
34
+ while (consumedTokens > 0) {
35
+ if (current === undefined) {
36
+ break;
37
+ }
38
+ children.push(current.node);
39
+ consumedTokens = consumedTokens - current.node.countTokens();
40
+ current = current.previous;
41
+ currentCount--;
42
+ }
43
+ node.setChildren(children.reverse());
44
+ this.nodes = { node, previous: current };
45
+ this.nodeCount = currentCount + 1;
46
+ return this;
25
47
  }
26
48
  popNode() {
27
- return this.nodes.pop();
49
+ if (this.nodes === undefined) {
50
+ return undefined;
51
+ }
52
+ const ret = this.nodes.node;
53
+ this.nodes = this.nodes.previous;
54
+ this.nodeCount--;
55
+ return ret;
28
56
  }
29
57
  getNodes() {
30
- return this.nodes;
58
+ const ret = new Array(this.nodeCount);
59
+ let current = this.nodes;
60
+ for (let index = this.nodeCount - 1; index >= 0; index--) {
61
+ if (current === undefined) {
62
+ break;
63
+ }
64
+ ret[index] = current.node;
65
+ current = current.previous;
66
+ }
67
+ return ret;
31
68
  }
32
69
  setNodes(n) {
33
- this.nodes = n;
70
+ this.nodes = undefined;
71
+ this.nodeCount = 0;
72
+ for (const node of n) {
73
+ this.nodes = { node, previous: this.nodes };
74
+ this.nodeCount++;
75
+ }
34
76
  }
35
77
  getTokens() {
36
78
  return this.tokens;
@@ -50,18 +50,25 @@ class DeleteInternal {
50
50
  let targetType = undefined;
51
51
  const target = node.findDirectExpression(Expressions.Target);
52
52
  if (target) {
53
+ const targetName = target.concatTokens();
53
54
  let tabl = undefined;
54
- const localVariable = input.scope.findVariable(target.concatTokens());
55
+ const localVariable = input.scope.findVariable(targetName);
55
56
  if (localVariable === undefined && node.getChildren().length === 5 && node.getChildren()[2].concatTokens().toUpperCase() === "FROM") {
56
57
  // it might be a database table
57
- const found = (_a = input.scope.getDDIC()) === null || _a === void 0 ? void 0 : _a.lookupTableOrView(target.concatTokens());
58
+ const found = (_a = input.scope.getDDIC()) === null || _a === void 0 ? void 0 : _a.lookupTableOrView(targetName);
58
59
  if ((found === null || found === void 0 ? void 0 : found.object) !== undefined) {
59
60
  tabl = found;
60
61
  input.scope.getDDICReferences().addUsing(input.scope.getParentObj(), { object: tabl.object });
61
62
  }
62
63
  }
63
64
  if (tabl === undefined) {
64
- targetType = target_1.Target.runSyntax(target, input);
65
+ const ambigiousVoids = input.scope.getRegistry().getConfig().getSyntaxSetttings().ambigiousVoids || [];
66
+ if (ambigiousVoids.some(name => name.toUpperCase() === targetName.toUpperCase())) {
67
+ targetType = basic_1.VoidType.get(targetName);
68
+ }
69
+ else {
70
+ targetType = target_1.Target.runSyntax(target, input);
71
+ }
65
72
  if (node.findDirectTokenByText("TABLE") === undefined
66
73
  && node.findDirectTokenByText("ADJACENT") === undefined
67
74
  && (node.findDirectTokenByText("FROM") || node.findDirectTokenByText("INDEX"))
@@ -78,6 +78,7 @@ class Config {
78
78
  languageVersion: langVer,
79
79
  errorNamespace: "^(Z|Y|LCL\_|TY\_|LIF\_)",
80
80
  globalConstants: [],
81
+ ambigiousVoids: [],
81
82
  globalMacros: [],
82
83
  },
83
84
  rules: rules,
@@ -128,6 +129,12 @@ class Config {
128
129
  // remove duplicates,
129
130
  this.config.syntax.globalConstants = [...new Set(this.config.syntax.globalConstants)];
130
131
  }
132
+ if (this.config.syntax.ambigiousVoids === undefined) {
133
+ this.config.syntax.ambigiousVoids = [];
134
+ }
135
+ else {
136
+ this.config.syntax.ambigiousVoids = [...new Set(this.config.syntax.ambigiousVoids)];
137
+ }
131
138
  if (this.config.global.skipIncludesWithoutMain === undefined) {
132
139
  this.config.global.skipIncludesWithoutMain = false;
133
140
  }
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.119.59";
78
+ return "2.119.61";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -59,6 +59,7 @@ class DangerousStatementConf extends _basic_rule_config_1.BasicRuleConfig {
59
59
  this.insertTextpool = true;
60
60
  this.deleteDynpro = true;
61
61
  this.exportDynpro = true;
62
+ this.editorCallForReport = true;
62
63
  /** Finds instances of dynamic SQL: SELECT, UPDATE, DELETE, INSERT, MODIFY */
63
64
  this.dynamicSQL = true;
64
65
  /** Ignore dynamic SQL in IF_RAP_QUERY_PROVIDER~SELECT implementations */
@@ -143,6 +144,11 @@ dynamic SQL can potentially create SQL injection problems`,
143
144
  else if (this.conf.exportDynpro && statement instanceof Statements.ExportDynpro) {
144
145
  message = "EXPORT DYNPRO";
145
146
  }
147
+ else if (this.conf.editorCallForReport
148
+ && statement instanceof Statements.EditorCall
149
+ && statementNode.findDirectTokenByText("REPORT")) {
150
+ message = "EDITOR-CALL FOR REPORT";
151
+ }
146
152
  if (message) {
147
153
  issues.push(issue_1.Issue.atStatement(file, statementNode, this.getDescription(message), this.getMetadata().key, this.conf.severity));
148
154
  }
@@ -342,6 +342,7 @@ Make sure to test the downported code, it might not always be completely correct
342
342
  const lowConfig = this.lowReg.getConfig().get();
343
343
  highConfig.syntax.errorNamespace = lowConfig.syntax.errorNamespace;
344
344
  highConfig.syntax.globalConstants = lowConfig.syntax.globalConstants;
345
+ highConfig.syntax.ambigiousVoids = lowConfig.syntax.ambigiousVoids;
345
346
  highConfig.syntax.globalMacros = lowConfig.syntax.globalMacros;
346
347
  this.highReg = new registry_1.Registry();
347
348
  for (const o of this.lowReg.getObjects()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.119.59",
3
+ "version": "2.119.61",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",