@abaplint/transpiler 2.13.78 → 2.13.81

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,11 +5,13 @@ import { Chunk } from "../chunk";
5
5
  export declare class MethodCallTranspiler implements IExpressionTranspiler {
6
6
  private readonly postName;
7
7
  private readonly method;
8
- /** @param postName inserted between the method name and the parameters, eg. ".bind(this)"
9
- * @param method the already resolved method reference, saves looking it up again */
8
+ private readonly discardResult;
9
+ /** @param postName inserted between the method name and the parameters, eg. ".bind(this)"
10
+ * @param method the already resolved method reference, saves looking it up again
11
+ * @param discardResult the RETURNING value of this call is not consumed */
10
12
  constructor(postName?: string, method?: {
11
13
  def: Types.MethodDefinition;
12
14
  name: string;
13
- });
15
+ }, discardResult?: boolean);
14
16
  transpile(node: Nodes.ExpressionNode, traversal: Traversal): Chunk;
15
17
  }
@@ -8,11 +8,14 @@ const chunk_1 = require("../chunk");
8
8
  class MethodCallTranspiler {
9
9
  postName;
10
10
  method;
11
- /** @param postName inserted between the method name and the parameters, eg. ".bind(this)"
12
- * @param method the already resolved method reference, saves looking it up again */
13
- constructor(postName = "", method) {
11
+ discardResult;
12
+ /** @param postName inserted between the method name and the parameters, eg. ".bind(this)"
13
+ * @param method the already resolved method reference, saves looking it up again
14
+ * @param discardResult the RETURNING value of this call is not consumed */
15
+ constructor(postName = "", method, discardResult = false) {
14
16
  this.postName = postName;
15
17
  this.method = method;
18
+ this.discardResult = discardResult;
16
19
  }
17
20
  transpile(node, traversal) {
18
21
  let post = "";
@@ -23,7 +26,8 @@ class MethodCallTranspiler {
23
26
  const scope = traversal.findCurrentScopeByToken(nameToken);
24
27
  const m = this.method ?? traversal.findMethodReference(nameToken, scope);
25
28
  let name = nameToken.getStr().toLowerCase();
26
- if (traversal.isBuiltinMethod(nameToken)) {
29
+ const isBuiltin = traversal.isBuiltinMethod(nameToken);
30
+ if (isBuiltin) {
27
31
  // todo: this is not correct, the method name might be shadowed
28
32
  name = "abap.builtin." + name + "(";
29
33
  if (name === "abap.builtin.line_exists(" || name === "abap.builtin.line_index(") {
@@ -57,9 +61,14 @@ class MethodCallTranspiler {
57
61
  if (step === undefined) {
58
62
  throw new Error("MethodCallTranspiler, unexpected node");
59
63
  }
64
+ // "IS SUPPLIED" on a RETURNING parameter is true when the call is functional,
65
+ // the flag is only passed along when the value of this very call is consumed
66
+ const returning = isBuiltin === true || this.discardResult === true
67
+ ? undefined
68
+ : m?.def.getParameters().getReturning()?.getName().toLowerCase();
60
69
  const ret = new chunk_1.Chunk();
61
70
  ret.append(name, nameToken, traversal);
62
- ret.appendChunk(new method_call_param_1.MethodCallParamTranspiler(m?.def).transpile(step, traversal));
71
+ ret.appendChunk(new method_call_param_1.MethodCallParamTranspiler(m?.def, returning).transpile(step, traversal));
63
72
  ret.appendString(post + ")");
64
73
  return ret;
65
74
  }
@@ -3,5 +3,9 @@ import { IExpressionTranspiler } from "./_expression_transpiler";
3
3
  import { Traversal } from "../traversal";
4
4
  import { Chunk } from "../chunk";
5
5
  export declare class MethodCallChainTranspiler implements IExpressionTranspiler {
6
+ private readonly discardResult;
7
+ /** @param discardResult the value of the last call in the chain is not consumed,
8
+ * ie. the chain is a standalone CALL statement */
9
+ constructor(discardResult?: boolean);
6
10
  transpile(node: Nodes.ExpressionNode, traversal: Traversal): Chunk;
7
11
  }
@@ -6,9 +6,17 @@ const traversal_1 = require("../traversal");
6
6
  const chunk_1 = require("../chunk");
7
7
  const method_call_1 = require("./method_call");
8
8
  class MethodCallChainTranspiler {
9
+ discardResult;
10
+ /** @param discardResult the value of the last call in the chain is not consumed,
11
+ * ie. the chain is a standalone CALL statement */
12
+ constructor(discardResult = false) {
13
+ this.discardResult = discardResult;
14
+ }
9
15
  transpile(node, traversal) {
10
16
  let ret = new chunk_1.Chunk();
11
17
  const children = node.getChildren();
18
+ const calls = node.findDirectExpressions(core_1.Expressions.MethodCall);
19
+ const lastCall = calls[calls.length - 1];
12
20
  for (const c of children) {
13
21
  if (c instanceof core_1.Nodes.ExpressionNode && c.get() instanceof core_1.Expressions.MethodCall) {
14
22
  const isFirst = c === node.getFirstChild();
@@ -26,9 +34,10 @@ class MethodCallChainTranspiler {
26
34
  method = traversal.findMethodReference(nameToken, traversal.findCurrentScopeByToken(nameToken));
27
35
  prefix = traversal.constructorPrototypePrefix(nameToken, method?.def, enclosingClass);
28
36
  }
37
+ const discard = this.discardResult === true && c === lastCall;
29
38
  const sub = prefix === undefined
30
- ? traversal.traverse(c)
31
- : new method_call_1.MethodCallTranspiler(".bind(this)", method).transpile(c, traversal);
39
+ ? new method_call_1.MethodCallTranspiler("", undefined, discard).transpile(c, traversal)
40
+ : new method_call_1.MethodCallTranspiler(".bind(this)", method, discard).transpile(c, traversal);
32
41
  if (sub.getCode().startsWith("abap.builtin.")
33
42
  || sub.getCode().startsWith("await abap.builtin.")) {
34
43
  ret.appendChunk(sub);
@@ -5,6 +5,12 @@ import { Traversal } from "../traversal";
5
5
  import { IExpressionTranspiler } from "./_expression_transpiler";
6
6
  export declare class MethodCallParamTranspiler implements IExpressionTranspiler {
7
7
  private readonly m;
8
- constructor(m?: abaplint.Types.MethodDefinition);
8
+ private readonly suppliedReturning;
9
+ /** On a real system "RETURNING IS SUPPLIED" is true exactly when the method is called
10
+ * functionally, so the caller has to say so.
11
+ * @param m the resolved method definition
12
+ * @param suppliedReturning name of the RETURNING parameter to flag as supplied,
13
+ * ie. the call is functional and the value is consumed */
14
+ constructor(m?: abaplint.Types.MethodDefinition, suppliedReturning?: string);
9
15
  transpile(node: Nodes.ExpressionNode, traversal: Traversal): Chunk;
10
16
  }
@@ -3,32 +3,43 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MethodCallParamTranspiler = void 0;
4
4
  const core_1 = require("@abaplint/core");
5
5
  const chunk_1 = require("../chunk");
6
+ const parameter_list_s_1 = require("./parameter_list_s");
6
7
  class MethodCallParamTranspiler {
7
8
  m;
8
- constructor(m) {
9
+ suppliedReturning;
10
+ /** On a real system "RETURNING IS SUPPLIED" is true exactly when the method is called
11
+ * functionally, so the caller has to say so.
12
+ * @param m the resolved method definition
13
+ * @param suppliedReturning name of the RETURNING parameter to flag as supplied,
14
+ * ie. the call is functional and the value is consumed */
15
+ constructor(m, suppliedReturning) {
9
16
  this.m = m;
17
+ this.suppliedReturning = suppliedReturning;
10
18
  }
11
19
  transpile(node, traversal) {
12
20
  let name = "";
13
21
  if (!(node.get() instanceof core_1.Expressions.MethodCallParam)) {
14
22
  throw new Error("MethodCallParam, unexpected node, " + node?.get().constructor.name);
15
23
  }
24
+ // the RETURNING parameter is passed along when the call is functional, see the constructor
25
+ const extra = this.suppliedReturning === undefined ? "" : this.suppliedReturning + ": 1";
16
26
  const source = node.findDirectExpression(core_1.Expressions.Source);
17
27
  if (source) {
18
28
  const def = this.m?.getParameters().getDefaultImporting()?.toLowerCase();
19
29
  if (this.m === undefined || def === undefined) {
30
+ // the input is not an object, so there is nowhere to put the RETURNING flag
20
31
  return traversal.traverse(source);
21
32
  }
22
33
  else {
23
34
  return new chunk_1.Chunk()
24
35
  .appendString("{" + def + ": ")
25
36
  .appendChunk(traversal.traverse(source))
26
- .appendString("}");
37
+ .appendString(extra === "" ? "}" : ", " + extra + "}");
27
38
  }
28
39
  }
29
40
  const parameters = node.findDirectExpression(core_1.Expressions.ParameterListS);
30
41
  if (parameters) {
31
- return traversal.traverse(parameters);
42
+ return new parameter_list_s_1.ParameterListSTranspiler(extra).transpile(parameters, traversal);
32
43
  }
33
44
  else {
34
45
  const params = node.findDirectExpression(core_1.Expressions.MethodParameters);
@@ -43,7 +54,13 @@ class MethodCallParamTranspiler {
43
54
  }
44
55
  }
45
56
  name = name.replace(/}{/g, ", ");
46
- return new chunk_1.Chunk(name);
57
+ if (extra === "") {
58
+ return new chunk_1.Chunk(name);
59
+ }
60
+ else if (name === "") {
61
+ return new chunk_1.Chunk("{" + extra + "}");
62
+ }
63
+ return new chunk_1.Chunk(name.replace(/}$/, ", " + extra + "}"));
47
64
  }
48
65
  }
49
66
  exports.MethodCallParamTranspiler = MethodCallParamTranspiler;
@@ -3,5 +3,8 @@ import { IExpressionTranspiler } from "./_expression_transpiler";
3
3
  import { Traversal } from "../traversal";
4
4
  import { Chunk } from "../chunk";
5
5
  export declare class ParameterListSTranspiler implements IExpressionTranspiler {
6
+ private readonly extra;
7
+ /** @param extra appended as an additional field of the emitted object, eg. "result: 1" */
8
+ constructor(extra?: string);
6
9
  transpile(node: Nodes.ExpressionNode, traversal: Traversal): Chunk;
7
10
  }
@@ -4,6 +4,11 @@ exports.ParameterListSTranspiler = void 0;
4
4
  const core_1 = require("@abaplint/core");
5
5
  const chunk_1 = require("../chunk");
6
6
  class ParameterListSTranspiler {
7
+ extra;
8
+ /** @param extra appended as an additional field of the emitted object, eg. "result: 1" */
9
+ constructor(extra = "") {
10
+ this.extra = extra;
11
+ }
7
12
  transpile(node, traversal) {
8
13
  const parameters = [];
9
14
  for (const c of node.getChildren()) {
@@ -11,7 +16,8 @@ class ParameterListSTranspiler {
11
16
  parameters.push(traversal.traverse(c));
12
17
  }
13
18
  }
14
- return new chunk_1.Chunk().appendString("{").join(parameters).appendString("}");
19
+ const post = this.extra === "" ? "}" : ", " + this.extra + "}";
20
+ return new chunk_1.Chunk().appendString("{").join(parameters).appendString(post);
15
21
  }
16
22
  }
17
23
  exports.ParameterListSTranspiler = ParameterListSTranspiler;
@@ -55,7 +55,8 @@ class CallTranspiler {
55
55
  pre = build.pre + pre;
56
56
  post += build.post;
57
57
  }
58
- const chainChunk = traversal.traverse(chain);
58
+ // without RECEIVING the value of the last call in the chain is thrown away
59
+ const chainChunk = new expressions_1.MethodCallChainTranspiler(receiving === undefined).transpile(chain, traversal);
59
60
  let chainCode = chainChunk.getCode();
60
61
  if (chainCode.startsWith("await super.constructor(")) {
61
62
  // semantics of constructors in JS vs ABAP is different, so the "constructor_" has been introduced,
@@ -128,6 +128,11 @@ class MethodImplementationTranspiler {
128
128
  }
129
129
  }
130
130
  else if (identifier.getMeta().includes("returning" /* abaplint.IdentifierMeta.MethodReturning */)) {
131
+ // the caller flags a consumed RETURNING value in INPUT, see MethodCallParamTranspiler,
132
+ // so "result IS SUPPLIED" needs the parameter even if the method has nothing else
133
+ if (unique === "") {
134
+ unique = "INPUT";
135
+ }
131
136
  after = after + transpile_types_1.TranspileTypes.declare(identifier) + "\n";
132
137
  }
133
138
  }
@@ -56,6 +56,7 @@ class SelectTranspiler {
56
56
  throw new Error("SelectTranspiler, UNION DISTINCT todo");
57
57
  }
58
58
  let target = "undefined";
59
+ let intoCorrespondingStructure = false;
59
60
  if (targetOverride) {
60
61
  // SelectLoop structure uses override
61
62
  target = targetOverride;
@@ -67,7 +68,9 @@ class SelectTranspiler {
67
68
  target = traversal.traverse(node.findFirstExpression(abaplint.Expressions.SQLIntoList)).getCode();
68
69
  }
69
70
  else if (node.findFirstExpression(abaplint.Expressions.SQLIntoStructure)) {
70
- target = traversal.traverse(node.findFirstExpression(abaplint.Expressions.SQLIntoStructure)).getCode();
71
+ const into = node.findFirstExpression(abaplint.Expressions.SQLIntoStructure);
72
+ target = traversal.traverse(into).getCode();
73
+ intoCorrespondingStructure = into.findDirectTokenByText("CORRESPONDING") !== undefined;
71
74
  }
72
75
  const tokens = node.getTokens();
73
76
  const isDistinct = tokens[0]?.getStr().toUpperCase() === "SELECT"
@@ -145,6 +148,9 @@ class SelectTranspiler {
145
148
  if (concat.includes(" APPENDING TABLE ") || concat.includes(" APPENDING CORRESPONDING FIELDS OF TABLE ")) {
146
149
  runtimeOptionsList.push(`appending: true`);
147
150
  }
151
+ if (intoCorrespondingStructure) {
152
+ runtimeOptionsList.push(`corresponding: true`);
153
+ }
148
154
  if (runtimeOptionsList.length > 0) {
149
155
  runtimeOptions = `, {` + runtimeOptionsList.join(", ") + `}`;
150
156
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler",
3
- "version": "2.13.78",
3
+ "version": "2.13.81",
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.43",
32
+ "@abaplint/core": "^2.120.45",
33
33
  "source-map": "^0.8.0"
34
34
  },
35
35
  "devDependencies": {