@abaplint/transpiler 2.12.9 → 2.12.11
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.
|
@@ -3,4 +3,8 @@ import { Traversal } from "../traversal";
|
|
|
3
3
|
import { Chunk } from "../chunk";
|
|
4
4
|
export declare class ValueBodyTranspiler {
|
|
5
5
|
transpile(typ: Nodes.ExpressionNode, body: Nodes.ExpressionNode, traversal: Traversal): Chunk;
|
|
6
|
+
private buildForChain;
|
|
7
|
+
private appendBlocks;
|
|
8
|
+
private appendBlock;
|
|
9
|
+
private blocksToString;
|
|
6
10
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ValueBodyTranspiler = void 0;
|
|
4
4
|
const core_1 = require("@abaplint/core");
|
|
5
|
+
const traversal_1 = require("../traversal");
|
|
5
6
|
const chunk_1 = require("../chunk");
|
|
6
7
|
const type_name_or_infer_1 = require("./type_name_or_infer");
|
|
7
8
|
const value_body_line_1 = require("./value_body_line");
|
|
@@ -24,7 +25,9 @@ class ValueBodyTranspiler {
|
|
|
24
25
|
let post = "";
|
|
25
26
|
let extraFields = "";
|
|
26
27
|
const hasLines = body.findDirectExpression(core_1.Expressions.ValueBodyLine) !== undefined;
|
|
27
|
-
|
|
28
|
+
const children = body.getChildren();
|
|
29
|
+
for (let i = 0; i < children.length; i++) {
|
|
30
|
+
const child = children[i];
|
|
28
31
|
if (child.get() instanceof core_1.Expressions.FieldAssignment && child instanceof core_1.Nodes.ExpressionNode) {
|
|
29
32
|
const transpiled = new field_assignment_1.FieldAssignmentTranspiler().transpile(child, traversal, context).getCode();
|
|
30
33
|
if (hasLines === false) {
|
|
@@ -50,15 +53,58 @@ class ValueBodyTranspiler {
|
|
|
50
53
|
ret.appendString(".set(" + source.getCode() + ".clone())");
|
|
51
54
|
}
|
|
52
55
|
else if (child.get() instanceof core_1.Expressions.For && child instanceof core_1.Nodes.ExpressionNode) {
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
const forNodes = [];
|
|
57
|
+
let idx = i;
|
|
58
|
+
while (idx < children.length) {
|
|
59
|
+
const candidate = children[idx];
|
|
60
|
+
if (candidate.get() instanceof core_1.Expressions.For && candidate instanceof core_1.Nodes.ExpressionNode) {
|
|
61
|
+
forNodes.push(candidate);
|
|
62
|
+
idx++;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
55
67
|
}
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
i = idx - 1;
|
|
69
|
+
const result = this.buildForChain(forNodes, typ, traversal, body);
|
|
70
|
+
ret = result.chunk;
|
|
71
|
+
post = result.post;
|
|
72
|
+
}
|
|
73
|
+
else if (child instanceof core_1.Nodes.TokenNode && child.getFirstToken().getStr().toUpperCase() === "DEFAULT") {
|
|
74
|
+
// note: this is last in the body, so its okay to prepend and postpend
|
|
75
|
+
const sources = body.findDirectExpressions(core_1.Expressions.Source);
|
|
76
|
+
const deflt = traversal.traverse(sources[1]).getCode();
|
|
77
|
+
const pre = `(await (async () => { try { return `;
|
|
78
|
+
ret = new chunk_1.Chunk().appendString(pre + ret.getCode());
|
|
79
|
+
post += `; } catch (error) { if (abap.isLineNotFound(error)) { return ${deflt}; } throw error; } })())`;
|
|
80
|
+
}
|
|
81
|
+
else if (child instanceof core_1.Nodes.TokenNode && child.getFirstToken().getStr().toUpperCase() === "OPTIONAL") {
|
|
82
|
+
// note: this is last in the body, so its okay to prepend and postpend
|
|
83
|
+
const pre = `(await (async () => { try { return `;
|
|
84
|
+
ret = new chunk_1.Chunk().appendString(pre + ret.getCode());
|
|
85
|
+
post += `; } catch (error) { if (abap.isLineNotFound(error)) { return ${transpile_types_1.TranspileTypes.toType(context)}; } throw error; } })())`;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
throw new Error("ValueBodyTranspiler, unknown " + child.get().constructor.name + " \"" + child.concatTokens()) + "\"";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return ret.appendString(post);
|
|
92
|
+
}
|
|
93
|
+
buildForChain(forNodes, typ, traversal, body) {
|
|
94
|
+
const val = new type_name_or_infer_1.TypeNameOrInfer().transpile(typ, traversal).getCode();
|
|
95
|
+
const chunk = new chunk_1.Chunk();
|
|
96
|
+
const preLoopDecls = [];
|
|
97
|
+
const descriptors = [];
|
|
98
|
+
const levelIndents = [];
|
|
99
|
+
let uniqueCounter = 1;
|
|
100
|
+
for (const child of forNodes) {
|
|
101
|
+
const loop = child.findDirectExpression(core_1.Expressions.InlineLoopDefinition);
|
|
102
|
+
if (loop) {
|
|
103
|
+
if (["THEN", "UNTIL", "WHILE", "FROM", "TO", "GROUPS"].some(token => child.findDirectTokenByText(token))) {
|
|
58
104
|
throw new Error("ValueBody FOR todo, " + body.concatTokens());
|
|
59
105
|
}
|
|
60
106
|
let loopWhere = "";
|
|
61
|
-
const whereNode = child
|
|
107
|
+
const whereNode = child.findDirectExpression(core_1.Expressions.ComponentCond);
|
|
62
108
|
if (whereNode) {
|
|
63
109
|
const where = traversal.traverse(whereNode).getCode();
|
|
64
110
|
loopWhere = `, {"where": async ` + where + `}`;
|
|
@@ -70,51 +116,176 @@ class ValueBodyTranspiler {
|
|
|
70
116
|
let targetDeclare = "";
|
|
71
117
|
let targetAction = "";
|
|
72
118
|
const fs = loop.findDirectExpression(core_1.Expressions.TargetFieldSymbol);
|
|
119
|
+
const uniqueName = `unique${uniqueCounter++}`;
|
|
73
120
|
if (fs) {
|
|
74
121
|
targetDeclare = new statements_1.FieldSymbolTranspiler().transpile(fs, traversal).getCode();
|
|
75
122
|
const targetName = new source_field_symbol_1.SourceFieldSymbolTranspiler().transpile(fs, traversal).getCode();
|
|
76
|
-
targetAction = `${targetName}.assign(
|
|
123
|
+
targetAction = `${targetName}.assign(${uniqueName});`;
|
|
77
124
|
}
|
|
78
125
|
else {
|
|
79
126
|
const field = traversal.traverse(loop.findDirectExpression(core_1.Expressions.TargetField));
|
|
80
127
|
if (field === undefined) {
|
|
81
128
|
throw new Error("ValueBody FOR empty field todo, " + body.concatTokens());
|
|
82
129
|
}
|
|
83
|
-
targetAction = `const ${field.getCode()} =
|
|
130
|
+
targetAction = `const ${field.getCode()} = ${uniqueName}.clone();`;
|
|
84
131
|
}
|
|
85
132
|
const llet = child.findDirectExpression(core_1.Expressions.Let);
|
|
86
133
|
if (llet) {
|
|
87
134
|
targetAction += new let_1.LetTranspiler().transpile(llet, traversal).getCode();
|
|
88
135
|
}
|
|
136
|
+
const preBodyStatements = [];
|
|
137
|
+
if (targetAction !== "") {
|
|
138
|
+
preBodyStatements.push(targetAction);
|
|
139
|
+
}
|
|
89
140
|
const source = traversal.traverse(loop.findDirectExpression(core_1.Expressions.Source)).getCode();
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
141
|
+
if (targetDeclare !== "") {
|
|
142
|
+
preLoopDecls.push(targetDeclare);
|
|
143
|
+
}
|
|
144
|
+
const descriptor = {
|
|
145
|
+
beforeLoop: [],
|
|
146
|
+
open: `for await (const ${uniqueName} of abap.statements.loop(${source}${loopWhere})) {`,
|
|
147
|
+
preBody: preBodyStatements,
|
|
148
|
+
postBody: [],
|
|
149
|
+
close: "}",
|
|
150
|
+
};
|
|
151
|
+
const loopTokens = loop.concatTokens().toUpperCase();
|
|
152
|
+
const indexTarget = loopTokens.includes("INDEX INTO") ? loop.findExpressionAfterToken("INTO") : undefined;
|
|
153
|
+
if (indexTarget && indexTarget instanceof core_1.Nodes.ExpressionNode) {
|
|
154
|
+
const indexCode = traversal.traverse(indexTarget).getCode();
|
|
155
|
+
const counterName = `unique${uniqueCounter++}`;
|
|
156
|
+
descriptor.beforeLoop.push(`let ${counterName} = 1;`);
|
|
157
|
+
descriptor.preBody.push(`const ${indexCode} = new abap.types.Integer().set(${counterName});`);
|
|
158
|
+
descriptor.postBody.push(`${counterName}++;`);
|
|
159
|
+
}
|
|
160
|
+
descriptors.push(descriptor);
|
|
98
161
|
}
|
|
99
|
-
else
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
162
|
+
else {
|
|
163
|
+
const counter = child.findDirectExpression(core_1.Expressions.InlineFieldDefinition);
|
|
164
|
+
if (counter === undefined) {
|
|
165
|
+
throw new Error("ValueBody FOR todo, " + body.concatTokens());
|
|
166
|
+
}
|
|
167
|
+
if (["GROUPS", "FROM", "TO"].some(token => child.findDirectTokenByText(token))) {
|
|
168
|
+
throw new Error("ValueBody FOR todo, " + body.concatTokens());
|
|
169
|
+
}
|
|
170
|
+
if (child.findDirectExpression(core_1.Expressions.ComponentCond)) {
|
|
171
|
+
throw new Error("ValueBody FOR todo, component cond, " + body.concatTokens());
|
|
172
|
+
}
|
|
173
|
+
const cond = child.findDirectExpression(core_1.Expressions.Cond);
|
|
174
|
+
if (cond === undefined) {
|
|
175
|
+
throw new Error("ValueBody FOR missing condition, " + body.concatTokens());
|
|
176
|
+
}
|
|
177
|
+
const hasUntil = child.findDirectTokenByText("UNTIL") !== undefined;
|
|
178
|
+
const hasWhile = child.findDirectTokenByText("WHILE") !== undefined;
|
|
179
|
+
if ((hasUntil ? 1 : 0) + (hasWhile ? 1 : 0) !== 1) {
|
|
180
|
+
throw new Error("ValueBody FOR todo, condition, " + body.concatTokens());
|
|
181
|
+
}
|
|
182
|
+
const fieldExpr = counter.findDirectExpression(core_1.Expressions.Field);
|
|
183
|
+
const fieldName = fieldExpr?.concatTokens().toLowerCase();
|
|
184
|
+
if (fieldName === undefined) {
|
|
185
|
+
throw new Error("ValueBody FOR todo, inline field, " + body.concatTokens());
|
|
186
|
+
}
|
|
187
|
+
const scope = traversal.findCurrentScopeByToken(counter.getFirstToken());
|
|
188
|
+
const variable = scope?.findVariable(fieldName);
|
|
189
|
+
if (variable === undefined) {
|
|
190
|
+
throw new Error("ValueBody FOR todo, variable, " + body.concatTokens());
|
|
191
|
+
}
|
|
192
|
+
const declare = transpile_types_1.TranspileTypes.declare(variable);
|
|
193
|
+
const counterName = traversal_1.Traversal.prefixVariable(fieldName);
|
|
194
|
+
const startSource = counter.findDirectExpression(core_1.Expressions.Source);
|
|
195
|
+
if (startSource === undefined) {
|
|
196
|
+
throw new Error("ValueBody FOR missing initial value, " + body.concatTokens());
|
|
197
|
+
}
|
|
198
|
+
const start = traversal.traverse(startSource).getCode();
|
|
199
|
+
const thenExpr = child.findExpressionAfterToken("THEN");
|
|
200
|
+
let incrementExpression = "";
|
|
201
|
+
if (thenExpr && thenExpr instanceof core_1.Nodes.ExpressionNode) {
|
|
202
|
+
incrementExpression = traversal.traverse(thenExpr).getCode();
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
incrementExpression = `abap.operators.add(${counterName}, new abap.types.Integer().set(1))`;
|
|
206
|
+
}
|
|
207
|
+
const incrementLine = `${counterName}.set(${incrementExpression});`;
|
|
208
|
+
const llet = child.findDirectExpression(core_1.Expressions.Let);
|
|
209
|
+
let letCode = "";
|
|
210
|
+
if (llet) {
|
|
211
|
+
letCode = new let_1.LetTranspiler().transpile(llet, traversal).getCode();
|
|
212
|
+
}
|
|
213
|
+
const condCode = traversal.traverse(cond).getCode();
|
|
214
|
+
const preCheck = hasWhile ? `if (!(${condCode})) {\n break;\n}` : "";
|
|
215
|
+
const postLoop = [];
|
|
216
|
+
postLoop.push(incrementLine);
|
|
217
|
+
if (hasUntil) {
|
|
218
|
+
postLoop.push(`if (${condCode}) {\n break;\n}`);
|
|
219
|
+
}
|
|
220
|
+
descriptors.push({
|
|
221
|
+
beforeLoop: [declare, `${counterName}.set(${start});`],
|
|
222
|
+
open: "while (true) {",
|
|
223
|
+
preBody: [preCheck, letCode].filter(s => s !== ""),
|
|
224
|
+
postBody: postLoop,
|
|
225
|
+
close: "}",
|
|
226
|
+
});
|
|
106
227
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
228
|
+
}
|
|
229
|
+
if (descriptors.length === 0) {
|
|
230
|
+
throw new Error("ValueBodyTranspiler FOR internal error");
|
|
231
|
+
}
|
|
232
|
+
chunk.appendString("await (async () => {\n");
|
|
233
|
+
this.appendBlocks(chunk, preLoopDecls, "");
|
|
234
|
+
chunk.appendString(`const VAL = ${val};\n`);
|
|
235
|
+
let indent = "";
|
|
236
|
+
for (const desc of descriptors) {
|
|
237
|
+
this.appendBlocks(chunk, desc.beforeLoop, indent);
|
|
238
|
+
chunk.appendString(indent + desc.open + "\n");
|
|
239
|
+
indent += " ";
|
|
240
|
+
levelIndents.push(indent);
|
|
241
|
+
this.appendBlocks(chunk, desc.preBody, indent);
|
|
242
|
+
}
|
|
243
|
+
chunk.appendString(indent + "VAL");
|
|
244
|
+
let post = ";\n";
|
|
245
|
+
for (let i = descriptors.length - 1; i >= 0; i--) {
|
|
246
|
+
const desc = descriptors[i];
|
|
247
|
+
const currentIndent = levelIndents[i] ?? "";
|
|
248
|
+
post += this.blocksToString(desc.postBody, currentIndent);
|
|
249
|
+
const parentIndent = currentIndent.substring(0, Math.max(0, currentIndent.length - 2));
|
|
250
|
+
post += parentIndent + desc.close + "\n";
|
|
251
|
+
}
|
|
252
|
+
post += "return VAL;\n})()";
|
|
253
|
+
return { chunk, post };
|
|
254
|
+
}
|
|
255
|
+
appendBlocks(chunk, blocks, indent) {
|
|
256
|
+
for (const block of blocks) {
|
|
257
|
+
this.appendBlock(chunk, block, indent);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
appendBlock(chunk, block, indent) {
|
|
261
|
+
if (block === "") {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const lines = block.split("\n");
|
|
265
|
+
for (const line of lines) {
|
|
266
|
+
const clean = line.replace(/\r/g, "");
|
|
267
|
+
if (clean.trim() === "") {
|
|
268
|
+
continue;
|
|
112
269
|
}
|
|
113
|
-
|
|
114
|
-
|
|
270
|
+
chunk.appendString(indent + clean + "\n");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
blocksToString(blocks, indent) {
|
|
274
|
+
let ret = "";
|
|
275
|
+
for (const block of blocks) {
|
|
276
|
+
if (block === "") {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const lines = block.split("\n");
|
|
280
|
+
for (const line of lines) {
|
|
281
|
+
const clean = line.replace(/\r/g, "");
|
|
282
|
+
if (clean.trim() === "") {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
ret += indent + clean + "\n";
|
|
115
286
|
}
|
|
116
287
|
}
|
|
117
|
-
return ret
|
|
288
|
+
return ret;
|
|
118
289
|
}
|
|
119
290
|
}
|
|
120
291
|
exports.ValueBodyTranspiler = ValueBodyTranspiler;
|
package/build/src/index.js
CHANGED
|
@@ -51,7 +51,7 @@ class Transpiler {
|
|
|
51
51
|
databaseSetup: dbSetup,
|
|
52
52
|
reg: reg,
|
|
53
53
|
};
|
|
54
|
-
progress?.set(reg.getObjectCount(
|
|
54
|
+
progress?.set(reg.getObjectCount().total, "Building");
|
|
55
55
|
for (const obj of reg.getObjects()) {
|
|
56
56
|
await progress?.tick("Building, " + obj.getName());
|
|
57
57
|
if (obj instanceof abaplint.Objects.TypePool) {
|
package/build/src/rearranger.js
CHANGED
|
@@ -101,6 +101,10 @@ class Rearranger {
|
|
|
101
101
|
|| !(secondLast.get() instanceof core_1.Expressions.ArithOperator)) {
|
|
102
102
|
return node;
|
|
103
103
|
}
|
|
104
|
+
const nestedArith = last.findDirectExpressions(core_1.Expressions.ArithOperator);
|
|
105
|
+
if (nestedArith.length === 0) {
|
|
106
|
+
return node;
|
|
107
|
+
}
|
|
104
108
|
const withoutLast = node.getChildren().slice(0, children.length - 1);
|
|
105
109
|
const flat = withoutLast.concat(last.getChildren());
|
|
106
110
|
node.setChildren(flat);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/transpiler",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.11",
|
|
4
4
|
"description": "Transpiler",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/src/index.d.ts",
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"author": "abaplint",
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@abaplint/core": "^2.113.
|
|
32
|
+
"@abaplint/core": "^2.113.240",
|
|
33
33
|
"source-map": "^0.7.6"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/chai": "^4.3.20",
|
|
37
37
|
"@types/mocha": "^10.0.10",
|
|
38
38
|
"chai": "^4.5.0",
|
|
39
|
-
"mocha": "^11.7.
|
|
39
|
+
"mocha": "^11.7.5",
|
|
40
40
|
"source-map-support": "^0.5.21",
|
|
41
41
|
"typescript": "^5.9.3"
|
|
42
42
|
}
|