@abaplint/transpiler 2.13.86 → 2.13.87

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.
@@ -5,5 +5,6 @@ import { Traversal } from "../traversal";
5
5
  export declare class SourceTranspiler implements IExpressionTranspiler {
6
6
  private readonly addGet;
7
7
  constructor(addGet?: boolean);
8
+ private concatOperands;
8
9
  transpile(node: Nodes.ExpressionNode, traversal: Traversal, context?: AbstractType): Chunk;
9
10
  }
@@ -15,10 +15,50 @@ class SourceTranspiler {
15
15
  constructor(addGet = false) {
16
16
  this.addGet = addGet;
17
17
  }
18
+ // the operands of a chain of & / && (the rearranger leaves them as a binary
19
+ // tree of Source nodes); an empty list when the node is not such a chain
20
+ concatOperands(node) {
21
+ const children = node.getChildren();
22
+ if (children.length !== 3) {
23
+ return [];
24
+ }
25
+ const op = children[1];
26
+ if (!(op instanceof core_1.Nodes.TokenNode) || (op.getFirstToken().getStr() !== "&&" && op.getFirstToken().getStr() !== "&")) {
27
+ return [];
28
+ }
29
+ const side = (c) => {
30
+ if (c instanceof core_1.Nodes.ExpressionNode && c.get() instanceof core_1.Expressions.Source) {
31
+ const inner = this.concatOperands(c);
32
+ return inner.length > 0 ? inner : [c];
33
+ }
34
+ const wrapped = new core_1.Nodes.ExpressionNode(new core_1.Expressions.Source());
35
+ wrapped.setChildren([c]);
36
+ return [wrapped];
37
+ };
38
+ return [...side(children[0]), ...side(children[2])];
39
+ }
18
40
  transpile(node, traversal, context) {
19
41
  let ret = new chunk_1.Chunk();
20
42
  const post = new chunk_1.Chunk();
21
43
  const children = node.getChildren();
44
+ // a & b & c ... : one flat concat([a, b, c]) instead of one nested
45
+ // concat( ) per operand (a long chain would otherwise exhaust the stack
46
+ // of a parser with a small budget, e.g. a service worker's)
47
+ const operands = this.concatOperands(node);
48
+ if (operands.length > 2) {
49
+ const flat = new chunk_1.Chunk().appendString("abap.operators.concat([");
50
+ for (let i = 0; i < operands.length; i++) {
51
+ if (i > 0) {
52
+ flat.appendString(",");
53
+ }
54
+ flat.appendChunk(new SourceTranspiler(false).transpile(operands[i], traversal, context));
55
+ }
56
+ flat.appendString("])");
57
+ if (this.addGet) {
58
+ flat.appendString(".get()");
59
+ }
60
+ return flat;
61
+ }
22
62
  // Pre-scan for unary prefix +/- tokens (WDashW / WPlusW) before any expression
23
63
  let prefixNegated = false;
24
64
  let startIdx = 0;
@@ -20,7 +20,11 @@ exports.DEFAULT_KEYWORDS = new Set([
20
20
  "throw", "throws", "transient", "true",
21
21
  "try", "typeof", "var", "void",
22
22
  "delete",
23
- "volatile", "while", "yield"
23
+ "volatile", "while", "yield",
24
+ // both produce a SyntaxError in the emitted module: they are reserved words
25
+ // in JavaScript and legal ABAP names. "super" is NOT in this list on purpose -
26
+ // the emitted code uses the JS `super` for ABAP's `super->method( )`, and
27
+ // escaping it turns that call into `$super.get().method()`
28
+ "case", "with"
24
29
  ]);
25
- // "with"
26
30
  //# sourceMappingURL=keywords.js.map
@@ -189,7 +189,23 @@ class Rearranger {
189
189
  return node;
190
190
  }
191
191
  const withoutLast = node.getChildren().slice(0, children.length - 1);
192
- const flat = withoutLast.concat(last.getChildren());
192
+ // The nested children come up so that precedence can be decided across
193
+ // the whole chain, and everything before the nested operator has to
194
+ // arrive as one operand. For "a * b / c" that is already true, b being a
195
+ // single Source. For "a * CONV f( b ) / c" it is not: CONV is five
196
+ // children, and hoisting them one by one puts the type name and the
197
+ // body beside the arithmetic, where the transpiler reads them as
198
+ // operands and loses the rest of the expression. So the head is wrapped
199
+ // back into one Source before it moves.
200
+ const nested = last.getChildren();
201
+ const firstOperator = nested.findIndex((c) => c instanceof core_1.Nodes.ExpressionNode && c.get() instanceof core_1.Expressions.ArithOperator);
202
+ let head = nested.slice(0, firstOperator);
203
+ if (head.length > 1) {
204
+ const operand = new core_1.Nodes.ExpressionNode(last.get());
205
+ operand.setChildren(head);
206
+ head = [operand];
207
+ }
208
+ const flat = withoutLast.concat(head, nested.slice(firstOperator));
193
209
  node.setChildren(flat);
194
210
  return node;
195
211
  }
@@ -87,16 +87,16 @@ class FunctionModuleTranspiler {
87
87
  direction = "importing";
88
88
  }
89
89
  // note: all directions are optional
90
- let name = p.name.toLowerCase();
91
- if (traversal.options?.keywords?.some(a => a === name)) {
92
- name += "_";
93
- }
94
- ret += `let ${name} = INPUT.${direction}?.${name};\n`;
90
+ const name = p.name.toLowerCase();
91
+ // a parameter named like a JavaScript keyword, RETURN on every BAPI,
92
+ // is declared the way the function body refers to it
93
+ const variable = traversal_1.Traversal.prefixVariable(name);
94
+ ret += `let ${variable} = INPUT.${direction}?.${name};\n`;
95
95
  const type = scope?.findVariable(name)?.getType();
96
96
  if (type !== undefined && p.optional === true) {
97
97
  // todo, set DEFAULT value
98
- ret += `if (${name} === undefined) {
99
- ${name} = ${transpile_types_1.TranspileTypes.toType(type)};
98
+ ret += `if (${variable} === undefined) {
99
+ ${variable} = ${transpile_types_1.TranspileTypes.toType(type)};
100
100
  }\n`;
101
101
  }
102
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler",
3
- "version": "2.13.86",
3
+ "version": "2.13.87",
4
4
  "description": "Transpiler",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/src/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "author": "abaplint",
30
30
  "license": "MIT",
31
31
  "dependencies": {
32
- "@abaplint/core": "^2.120.50",
32
+ "@abaplint/core": "^2.120.52",
33
33
  "source-map": "^0.8.0"
34
34
  },
35
35
  "devDependencies": {