@abaplint/transpiler 2.13.79 → 2.13.82
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.
- package/build/src/expressions/method_call.d.ts +5 -3
- package/build/src/expressions/method_call.js +14 -5
- package/build/src/expressions/method_call_chain.d.ts +4 -0
- package/build/src/expressions/method_call_chain.js +11 -2
- package/build/src/expressions/method_call_param.d.ts +7 -1
- package/build/src/expressions/method_call_param.js +21 -4
- package/build/src/expressions/parameter_list_s.d.ts +3 -0
- package/build/src/expressions/parameter_list_s.js +7 -1
- package/build/src/statements/call.js +2 -1
- package/build/src/statements/data.js +8 -1
- package/build/src/statements/method_implementation.js +5 -0
- package/build/src/statements/select.js +7 -1
- package/build/src/transpile_types.d.ts +3 -1
- package/build/src/transpile_types.js +4 -3
- package/package.json +2 -2
|
@@ -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
|
-
|
|
9
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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
|
-
?
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -92,12 +92,19 @@ class DataTranspiler {
|
|
|
92
92
|
value = "\n" + traversal_1.Traversal.prefixVariable(found.getName().toLowerCase()) + ".set(\"" + enumDefault + "\");";
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
+
let packedDecimals;
|
|
96
|
+
if (found.getType() instanceof abaplint.BasicTypes.PackedType) {
|
|
97
|
+
const decimals = node.findFirstExpression(abaplint.Expressions.Decimals)?.findFirstExpression(abaplint.Expressions.Integer);
|
|
98
|
+
if (decimals) {
|
|
99
|
+
packedDecimals = parseInt(decimals.concatTokens(), 10);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
95
102
|
this.variableName = traversal_1.Traversal.prefixVariable(traversal_1.Traversal.escapeNamespace(found.getName().toLowerCase()));
|
|
96
103
|
this.loopScoped = traversal.isInsideLoop(node);
|
|
97
104
|
const ret = new chunk_1.Chunk()
|
|
98
105
|
.appendString(this.loopScoped === true ? "var " : "let ")
|
|
99
106
|
.appendString(this.variableName)
|
|
100
|
-
.appendString(" = " + transpile_types_1.TranspileTypes.toType(found.getType()))
|
|
107
|
+
.appendString(" = " + transpile_types_1.TranspileTypes.toType(found.getType(), { packedDecimals }))
|
|
101
108
|
.appendString(";")
|
|
102
109
|
.appendString(value);
|
|
103
110
|
if (this.loopScoped === true && this.skipLoopScoping === false) {
|
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -4,5 +4,7 @@ export declare class TranspileTypes {
|
|
|
4
4
|
static declareStaticSkipVoid(pre: string, t: abaplint.TypedIdentifier): string;
|
|
5
5
|
/** this returns a function, so it doesnt throw when loading the code, only when running */
|
|
6
6
|
static toTypeFunction(type: abaplint.AbstractType): string;
|
|
7
|
-
static toType(type: abaplint.AbstractType
|
|
7
|
+
static toType(type: abaplint.AbstractType, options?: {
|
|
8
|
+
packedDecimals?: number;
|
|
9
|
+
}): string;
|
|
8
10
|
}
|
|
@@ -62,7 +62,7 @@ class TranspileTypes {
|
|
|
62
62
|
// return singleton,
|
|
63
63
|
return "(() => { let _t; return () => (_t ??= " + this.toType(type) + "); })()";
|
|
64
64
|
}
|
|
65
|
-
static toType(type) {
|
|
65
|
+
static toType(type, options) {
|
|
66
66
|
let resolved = "";
|
|
67
67
|
let extra = "";
|
|
68
68
|
if (type instanceof abaplint.BasicTypes.ObjectReferenceType
|
|
@@ -185,11 +185,12 @@ class TranspileTypes {
|
|
|
185
185
|
}
|
|
186
186
|
else if (type instanceof abaplint.BasicTypes.PackedType) {
|
|
187
187
|
resolved = "Packed";
|
|
188
|
+
const decimals = options?.packedDecimals ?? type.getDecimals();
|
|
188
189
|
if (type.getQualifiedName()) {
|
|
189
|
-
extra = "{length: " + type.getLength() + ", decimals: " +
|
|
190
|
+
extra = "{length: " + type.getLength() + ", decimals: " + decimals + ", qualifiedName: \"" + type.getQualifiedName() + "\"}";
|
|
190
191
|
}
|
|
191
192
|
else {
|
|
192
|
-
extra = "{length: " + type.getLength() + ", decimals: " +
|
|
193
|
+
extra = "{length: " + type.getLength() + ", decimals: " + decimals + "}";
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
else if (type instanceof abaplint.BasicTypes.NumericGenericType) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/transpiler",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.82",
|
|
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.
|
|
32
|
+
"@abaplint/core": "^2.120.45",
|
|
33
33
|
"source-map": "^0.8.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|