@abaplint/transpiler 2.12.10 → 2.12.12

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.
@@ -53,13 +53,13 @@ class CompareTranspiler {
53
53
  const field = concat.replace(" IS NOT REQUESTED", "").toLowerCase();
54
54
  return new chunk_1.Chunk().appendString(pre + "INPUT && INPUT." + field + " === undefined && INPUT.importing?." + field + " === undefined");
55
55
  }
56
- if (concat.startsWith("NOT ") || concat.includes(" IS NOT INSTANCE OF ")) {
57
- const cname = node.findDirectExpression(core_1.Expressions.ClassName)?.concatTokens();
58
- return new chunk_1.Chunk().appendString("abap.compare.instance_of(").appendChunk(s0).appendString(`, ${cname}) === false`);
59
- }
60
- else if (concat.includes(" IS INSTANCE OF ")) {
61
- const cname = node.findDirectExpression(core_1.Expressions.ClassName)?.concatTokens();
62
- return new chunk_1.Chunk().appendString("abap.compare.instance_of(").appendChunk(s0).appendString(`, ${cname})`);
56
+ if (concat.includes(" IS INSTANCE OF ")) {
57
+ const notted = concat.startsWith("NOT ") || concat.includes(" IS NOT INSTANCE OF ");
58
+ const falsed = notted ? " === false" : "";
59
+ const expr = node.findDirectExpression(core_1.Expressions.ClassName);
60
+ const cname = expr?.concatTokens();
61
+ const lookup = traversal.lookupClassOrInterface(cname, expr?.getFirstToken());
62
+ return new chunk_1.Chunk().appendString("abap.compare.instance_of(").appendChunk(s0).appendString(`, ${lookup})` + falsed);
63
63
  }
64
64
  }
65
65
  else if (sources.length === 2 && node.findDirectTokenByText("IN")) {
@@ -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
  }
@@ -25,7 +25,9 @@ class ValueBodyTranspiler {
25
25
  let post = "";
26
26
  let extraFields = "";
27
27
  const hasLines = body.findDirectExpression(core_1.Expressions.ValueBodyLine) !== undefined;
28
- for (const child of body.getChildren()) {
28
+ const children = body.getChildren();
29
+ for (let i = 0; i < children.length; i++) {
30
+ const child = children[i];
29
31
  if (child.get() instanceof core_1.Expressions.FieldAssignment && child instanceof core_1.Nodes.ExpressionNode) {
30
32
  const transpiled = new field_assignment_1.FieldAssignmentTranspiler().transpile(child, traversal, context).getCode();
31
33
  if (hasLines === false) {
@@ -51,117 +53,22 @@ class ValueBodyTranspiler {
51
53
  ret.appendString(".set(" + source.getCode() + ".clone())");
52
54
  }
53
55
  else if (child.get() instanceof core_1.Expressions.For && child instanceof core_1.Nodes.ExpressionNode) {
54
- const loop = child.findDirectExpression(core_1.Expressions.InlineLoopDefinition);
55
- if (loop) {
56
- if (["THEN", "UNTIL", "WHILE", "FROM", "TO", "GROUPS"].some(token => child.findDirectTokenByText(token))) {
57
- throw new Error("ValueBody FOR todo, " + body.concatTokens());
58
- }
59
- let loopWhere = "";
60
- const whereNode = child?.findDirectExpression(core_1.Expressions.ComponentCond);
61
- if (whereNode) {
62
- const where = traversal.traverse(whereNode).getCode();
63
- loopWhere = `, {"where": async ` + where + `}`;
64
- }
65
- const base = loop.findDirectExpression(core_1.Expressions.ValueBase);
66
- if (base) {
67
- throw new Error("ValueBody FOR todo, base, " + body.concatTokens());
68
- }
69
- let targetDeclare = "";
70
- let targetAction = "";
71
- const fs = loop.findDirectExpression(core_1.Expressions.TargetFieldSymbol);
72
- if (fs) {
73
- targetDeclare = new statements_1.FieldSymbolTranspiler().transpile(fs, traversal).getCode();
74
- const targetName = new source_field_symbol_1.SourceFieldSymbolTranspiler().transpile(fs, traversal).getCode();
75
- targetAction = `${targetName}.assign(unique1);`;
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++;
76
63
  }
77
64
  else {
78
- const field = traversal.traverse(loop.findDirectExpression(core_1.Expressions.TargetField));
79
- if (field === undefined) {
80
- throw new Error("ValueBody FOR empty field todo, " + body.concatTokens());
81
- }
82
- targetAction = `const ${field.getCode()} = unique1.clone();`;
83
- }
84
- const llet = child.findDirectExpression(core_1.Expressions.Let);
85
- if (llet) {
86
- targetAction += new let_1.LetTranspiler().transpile(llet, traversal).getCode();
65
+ break;
87
66
  }
88
- const source = traversal.traverse(loop.findDirectExpression(core_1.Expressions.Source)).getCode();
89
- const val = new type_name_or_infer_1.TypeNameOrInfer().transpile(typ, traversal).getCode();
90
- ret = new chunk_1.Chunk().appendString(`await (async () => {
91
- ${targetDeclare}
92
- const VAL = ${val};
93
- for await (const unique1 of abap.statements.loop(${source}${loopWhere})) {
94
- ${targetAction}
95
- VAL`);
96
- post = ";\n}\nreturn VAL;\n})()";
97
- }
98
- else {
99
- const counter = child.findDirectExpression(core_1.Expressions.InlineFieldDefinition);
100
- if (counter === undefined) {
101
- throw new Error("ValueBody FOR todo, " + body.concatTokens());
102
- }
103
- if (["GROUPS", "FROM", "TO"].some(token => child.findDirectTokenByText(token))) {
104
- throw new Error("ValueBody FOR todo, " + body.concatTokens());
105
- }
106
- if (child.findDirectExpression(core_1.Expressions.ComponentCond)) {
107
- throw new Error("ValueBody FOR todo, component cond, " + body.concatTokens());
108
- }
109
- const cond = child.findDirectExpression(core_1.Expressions.Cond);
110
- if (cond === undefined) {
111
- throw new Error("ValueBody FOR missing condition, " + body.concatTokens());
112
- }
113
- const hasUntil = child.findDirectTokenByText("UNTIL") !== undefined;
114
- const hasWhile = child.findDirectTokenByText("WHILE") !== undefined;
115
- if ((hasUntil ? 1 : 0) + (hasWhile ? 1 : 0) !== 1) {
116
- throw new Error("ValueBody FOR todo, condition, " + body.concatTokens());
117
- }
118
- const fieldExpr = counter.findDirectExpression(core_1.Expressions.Field);
119
- const fieldName = fieldExpr?.concatTokens().toLowerCase();
120
- if (fieldName === undefined) {
121
- throw new Error("ValueBody FOR todo, inline field, " + body.concatTokens());
122
- }
123
- const scope = traversal.findCurrentScopeByToken(counter.getFirstToken());
124
- const variable = scope?.findVariable(fieldName);
125
- if (variable === undefined) {
126
- throw new Error("ValueBody FOR todo, variable, " + body.concatTokens());
127
- }
128
- const declare = transpile_types_1.TranspileTypes.declare(variable);
129
- const counterName = traversal_1.Traversal.prefixVariable(fieldName);
130
- const startSource = counter.findDirectExpression(core_1.Expressions.Source);
131
- if (startSource === undefined) {
132
- throw new Error("ValueBody FOR missing initial value, " + body.concatTokens());
133
- }
134
- const start = traversal.traverse(startSource).getCode();
135
- const thenExpr = child.findExpressionAfterToken("THEN");
136
- let incrementExpression = "";
137
- if (thenExpr && thenExpr instanceof core_1.Nodes.ExpressionNode) {
138
- incrementExpression = traversal.traverse(thenExpr).getCode();
139
- }
140
- else {
141
- incrementExpression = `abap.operators.add(${counterName}, new abap.types.Integer().set(1))`;
142
- }
143
- const incrementLine = `${counterName}.set(${incrementExpression});`;
144
- const llet = child.findDirectExpression(core_1.Expressions.Let);
145
- let letCode = "";
146
- if (llet) {
147
- letCode = new let_1.LetTranspiler().transpile(llet, traversal).getCode();
148
- }
149
- const letSection = letCode === "" ? "" : " " + letCode.replace(/\n/g, "\n ") + "\n";
150
- const condCode = traversal.traverse(cond).getCode();
151
- const val = new type_name_or_infer_1.TypeNameOrInfer().transpile(typ, traversal).getCode();
152
- const preCheck = hasWhile ? ` if (!(${condCode})) {\n break;\n }\n` : "";
153
- let postLoop = ` ${incrementLine}\n`;
154
- if (hasUntil) {
155
- postLoop += ` if (${condCode}) {\n break;\n }\n`;
156
- }
157
- ret = new chunk_1.Chunk().appendString(`await (async () => {
158
- ${declare}
159
- ${counterName}.set(${start});
160
- const VAL = ${val};
161
- while (true) {
162
- ${preCheck}${letSection} VAL`);
163
- post = ";\n" + postLoop + "}\nreturn VAL;\n})()";
164
67
  }
68
+ i = idx - 1;
69
+ const result = this.buildForChain(forNodes, typ, traversal, body);
70
+ ret = result.chunk;
71
+ post = result.post;
165
72
  }
166
73
  else if (child instanceof core_1.Nodes.TokenNode && child.getFirstToken().getStr().toUpperCase() === "DEFAULT") {
167
74
  // note: this is last in the body, so its okay to prepend and postpend
@@ -183,6 +90,203 @@ ${preCheck}${letSection} VAL`);
183
90
  }
184
91
  return ret.appendString(post);
185
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))) {
104
+ throw new Error("ValueBody FOR todo, " + body.concatTokens());
105
+ }
106
+ let loopWhere = "";
107
+ const whereNode = child.findDirectExpression(core_1.Expressions.ComponentCond);
108
+ if (whereNode) {
109
+ const where = traversal.traverse(whereNode).getCode();
110
+ loopWhere = `, {"where": async ` + where + `}`;
111
+ }
112
+ const base = loop.findDirectExpression(core_1.Expressions.ValueBase);
113
+ if (base) {
114
+ throw new Error("ValueBody FOR todo, base, " + body.concatTokens());
115
+ }
116
+ let targetDeclare = "";
117
+ let targetAction = "";
118
+ const fs = loop.findDirectExpression(core_1.Expressions.TargetFieldSymbol);
119
+ const uniqueName = `unique${uniqueCounter++}`;
120
+ if (fs) {
121
+ targetDeclare = new statements_1.FieldSymbolTranspiler().transpile(fs, traversal).getCode();
122
+ const targetName = new source_field_symbol_1.SourceFieldSymbolTranspiler().transpile(fs, traversal).getCode();
123
+ targetAction = `${targetName}.assign(${uniqueName});`;
124
+ }
125
+ else {
126
+ const field = traversal.traverse(loop.findDirectExpression(core_1.Expressions.TargetField));
127
+ if (field === undefined) {
128
+ throw new Error("ValueBody FOR empty field todo, " + body.concatTokens());
129
+ }
130
+ targetAction = `const ${field.getCode()} = ${uniqueName}.clone();`;
131
+ }
132
+ const llet = child.findDirectExpression(core_1.Expressions.Let);
133
+ if (llet) {
134
+ targetAction += new let_1.LetTranspiler().transpile(llet, traversal).getCode();
135
+ }
136
+ const preBodyStatements = [];
137
+ if (targetAction !== "") {
138
+ preBodyStatements.push(targetAction);
139
+ }
140
+ const source = traversal.traverse(loop.findDirectExpression(core_1.Expressions.Source)).getCode();
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);
161
+ }
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
+ });
227
+ }
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;
269
+ }
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";
286
+ }
287
+ }
288
+ return ret;
289
+ }
186
290
  }
187
291
  exports.ValueBodyTranspiler = ValueBodyTranspiler;
188
292
  //# sourceMappingURL=value_body.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler",
3
- "version": "2.12.10",
3
+ "version": "2.12.12",
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.113.240",
32
+ "@abaplint/core": "^2.113.246",
33
33
  "source-map": "^0.7.6"
34
34
  },
35
35
  "devDependencies": {