@abaplint/transpiler 2.13.95 → 2.13.97

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.
Files changed (48) hide show
  1. package/build/src/chunk.js +2 -1
  2. package/build/src/db/schema_generation/pg_database_schema.js +3 -0
  3. package/build/src/db/schema_generation/snowflake_database_schema.js +3 -0
  4. package/build/src/db/schema_generation/sqlite_database_schema.js +3 -0
  5. package/build/src/expressions/reduce_body.js +12 -16
  6. package/build/src/expressions/source.d.ts +3 -1
  7. package/build/src/expressions/source.js +29 -5
  8. package/build/src/expressions/sql_cond.d.ts +1 -0
  9. package/build/src/expressions/sql_cond.js +15 -3
  10. package/build/src/expressions/value_body.js +25 -22
  11. package/build/src/statements/_dataset.d.ts +17 -0
  12. package/build/src/statements/_dataset.js +82 -0
  13. package/build/src/statements/_selection.d.ts +18 -0
  14. package/build/src/statements/_selection.js +82 -0
  15. package/build/src/statements/assign.js +9 -8
  16. package/build/src/statements/call.js +3 -3
  17. package/build/src/statements/call_function.js +10 -3
  18. package/build/src/statements/close_dataset.d.ts +1 -1
  19. package/build/src/statements/close_dataset.js +40 -2
  20. package/build/src/statements/create_data.js +1 -1
  21. package/build/src/statements/delete_dataset.d.ts +1 -1
  22. package/build/src/statements/delete_dataset.js +40 -2
  23. package/build/src/statements/generate_subroutine.d.ts +3 -1
  24. package/build/src/statements/generate_subroutine.js +72 -2
  25. package/build/src/statements/get_dataset.d.ts +1 -1
  26. package/build/src/statements/get_dataset.js +14 -2
  27. package/build/src/statements/loop.d.ts +1 -0
  28. package/build/src/statements/loop.js +12 -0
  29. package/build/src/statements/move.d.ts +2 -0
  30. package/build/src/statements/move.js +70 -1
  31. package/build/src/statements/open_dataset.d.ts +1 -1
  32. package/build/src/statements/open_dataset.js +32 -2
  33. package/build/src/statements/parameter.d.ts +2 -1
  34. package/build/src/statements/parameter.js +68 -2
  35. package/build/src/statements/perform.js +13 -1
  36. package/build/src/statements/read_dataset.d.ts +1 -1
  37. package/build/src/statements/read_dataset.js +16 -2
  38. package/build/src/statements/select.js +78 -13
  39. package/build/src/statements/select_option.d.ts +1 -1
  40. package/build/src/statements/select_option.js +63 -2
  41. package/build/src/statements/set_dataset.d.ts +1 -1
  42. package/build/src/statements/set_dataset.js +10 -2
  43. package/build/src/statements/sort.d.ts +2 -0
  44. package/build/src/statements/sort.js +33 -4
  45. package/build/src/statements/transfer.d.ts +1 -1
  46. package/build/src/statements/transfer.js +14 -2
  47. package/build/src/structures/class_definition.js +10 -9
  48. package/package.json +2 -2
@@ -170,7 +170,8 @@ class Chunk {
170
170
  }
171
171
  const indentationByLine = this.mappings.length > 0 ? [] : undefined;
172
172
  for (const l of this.raw.split("\n")) {
173
- if (l.startsWith("}")) {
173
+ // trimStart, a pre-indented closing brace must still close its level
174
+ if (l.trimStart().startsWith("}")) {
174
175
  i = i - 1;
175
176
  }
176
177
  // clamp so unbalanced braces never produce a negative indent/shift
@@ -95,6 +95,9 @@ class PGDatabaseSchema {
95
95
  else if (type instanceof abaplint.BasicTypes.IntegerType) {
96
96
  return `INT`;
97
97
  }
98
+ else if (type instanceof abaplint.BasicTypes.Integer8Type) {
99
+ return `BIGINT`;
100
+ }
98
101
  else if (type instanceof abaplint.BasicTypes.FloatType
99
102
  || type instanceof abaplint.BasicTypes.FloatingPointType) {
100
103
  return `REAL`;
@@ -94,6 +94,9 @@ class SnowflakeDatabaseSchema {
94
94
  else if (type instanceof abaplint.BasicTypes.IntegerType) {
95
95
  return `INT`;
96
96
  }
97
+ else if (type instanceof abaplint.BasicTypes.Integer8Type) {
98
+ return `NUMBER(19)`;
99
+ }
97
100
  else if (type instanceof abaplint.BasicTypes.FloatType
98
101
  || type instanceof abaplint.BasicTypes.FloatingPointType) {
99
102
  return `REAL`;
@@ -96,6 +96,9 @@ class SQLiteDatabaseSchema {
96
96
  else if (type instanceof abaplint.BasicTypes.IntegerType) {
97
97
  return `INT`;
98
98
  }
99
+ else if (type instanceof abaplint.BasicTypes.Integer8Type) {
100
+ return `INTEGER`;
101
+ }
99
102
  else if (type instanceof abaplint.BasicTypes.FloatType
100
103
  || type instanceof abaplint.BasicTypes.FloatingPointType) {
101
104
  return `REAL`;
@@ -31,22 +31,18 @@ class ReduceBodyTranspiler {
31
31
  for (const declaration of declarations) {
32
32
  ret.appendString(declaration + "\n");
33
33
  }
34
- let indent = "";
35
- const levelIndents = [];
34
+ // no manual indentation, Chunk.runIndentationLogic indents by brace depth,
35
+ // pre-indented closing braces would not be recognized and drift the indentation
36
36
  for (const descriptor of descriptors) {
37
- this.appendBlocks(ret, descriptor.beforeLoop, indent);
38
- ret.appendString(indent + descriptor.open + "\n");
39
- indent += " ";
40
- levelIndents.push(indent);
41
- this.appendBlocks(ret, descriptor.preBody, indent);
37
+ this.appendBlocks(ret, descriptor.beforeLoop);
38
+ ret.appendString(descriptor.open + "\n");
39
+ this.appendBlocks(ret, descriptor.preBody);
42
40
  }
43
- this.appendBlock(ret, this.transpileNext(body, traversal), indent);
41
+ this.appendBlock(ret, this.transpileNext(body, traversal));
44
42
  for (let i = descriptors.length - 1; i >= 0; i--) {
45
43
  const descriptor = descriptors[i];
46
- const currentIndent = levelIndents[i];
47
- this.appendBlocks(ret, descriptor.postBody, currentIndent);
48
- indent = currentIndent.substring(0, Math.max(0, currentIndent.length - 2));
49
- ret.appendString(indent + descriptor.close + "\n");
44
+ this.appendBlocks(ret, descriptor.postBody);
45
+ ret.appendString(descriptor.close + "\n");
50
46
  }
51
47
  ret.appendString(`return ${returnField};\n`);
52
48
  ret.appendString("})())");
@@ -266,15 +262,15 @@ class ReduceBodyTranspiler {
266
262
  }
267
263
  return ret;
268
264
  }
269
- appendBlocks(ret, blocks, indent) {
265
+ appendBlocks(ret, blocks) {
270
266
  for (const block of blocks) {
271
- this.appendBlock(ret, block, indent);
267
+ this.appendBlock(ret, block);
272
268
  }
273
269
  }
274
- appendBlock(ret, block, indent) {
270
+ appendBlock(ret, block) {
275
271
  for (const line of block.split("\n")) {
276
272
  if (line.trim() !== "") {
277
- ret.appendString(indent + line.replace(/\r/g, "") + "\n");
273
+ ret.appendString(line.replace(/\r/g, "") + "\n");
278
274
  }
279
275
  }
280
276
  }
@@ -4,7 +4,9 @@ import { IExpressionTranspiler } from "./_expression_transpiler";
4
4
  import { Traversal } from "../traversal";
5
5
  export declare class SourceTranspiler implements IExpressionTranspiler {
6
6
  private readonly addGet;
7
- constructor(addGet?: boolean);
7
+ private readonly int8;
8
+ /** int8: the calculation type is int8, each operation gets its left operand as an int8 */
9
+ constructor(addGet?: boolean, int8?: boolean);
8
10
  private concatOperands;
9
11
  transpile(node: Nodes.ExpressionNode, traversal: Traversal, context?: AbstractType): Chunk;
10
12
  }
@@ -9,11 +9,15 @@ const corresponding_body_1 = require("./corresponding_body");
9
9
  const filter_body_1 = require("./filter_body");
10
10
  const reduce_body_1 = require("./reduce_body");
11
11
  const transpile_types_1 = require("../transpile_types");
12
+ const let_1 = require("./let");
12
13
  const value_body_1 = require("./value_body");
13
14
  class SourceTranspiler {
14
15
  addGet;
15
- constructor(addGet = false) {
16
+ int8;
17
+ /** int8: the calculation type is int8, each operation gets its left operand as an int8 */
18
+ constructor(addGet = false, int8 = false) {
16
19
  this.addGet = addGet;
20
+ this.int8 = int8;
17
21
  }
18
22
  // the operands of a chain of & / && (the rearranger leaves them as a binary
19
23
  // tree of Source nodes); an empty list when the node is not such a chain
@@ -81,6 +85,8 @@ class SourceTranspiler {
81
85
  break;
82
86
  }
83
87
  }
88
+ // int8: whether the operand left of the next operator is already an int8
89
+ let leftIsInt8 = false;
84
90
  for (let i = startIdx; i < children.length; i++) {
85
91
  const c = children[i];
86
92
  const isLast = i === children.length - 1;
@@ -98,7 +104,18 @@ class SourceTranspiler {
98
104
  ret.appendChunk(traversal.traverse(c));
99
105
  }
100
106
  else if (c.get() instanceof core_1.Expressions.ArithOperator) {
101
- ret = new chunk_1.Chunk().appendChunk(traversal.traverse(c)).appendString("(").appendChunk(ret).appendString(",");
107
+ // "/" rounds in calculation type int8, the runtime's divide() does not know the target
108
+ const operator = this.int8 === true && c.concatTokens().trim() === "/"
109
+ ? new chunk_1.Chunk().append("abap.operators.divideInt8", c, traversal)
110
+ : traversal.traverse(c);
111
+ if (this.int8 === true && leftIsInt8 === false) {
112
+ ret = new chunk_1.Chunk().appendChunk(operator).appendString("(new abap.types.Integer8().set(").appendChunk(ret).appendString("),");
113
+ }
114
+ else {
115
+ ret = new chunk_1.Chunk().appendChunk(operator).appendString("(").appendChunk(ret).appendString(",");
116
+ }
117
+ // the result of an operation with an int8 operand is an int8
118
+ leftIsInt8 = true;
102
119
  post.appendString(")");
103
120
  if (this.addGet) {
104
121
  post.append(".get()", c, traversal);
@@ -115,7 +132,8 @@ class SourceTranspiler {
115
132
  }
116
133
  }
117
134
  else if (c.get() instanceof core_1.Expressions.Source) {
118
- ret.appendChunk(new SourceTranspiler(this.addGet).transpile(c, traversal));
135
+ ret.appendChunk(new SourceTranspiler(this.addGet, this.int8).transpile(c, traversal));
136
+ leftIsInt8 = c.findDirectExpression(core_1.Expressions.ArithOperator) !== undefined;
119
137
  }
120
138
  else if (c.get() instanceof core_1.Expressions.Arrow) {
121
139
  ret = new chunk_1.Chunk().appendString("(").appendChunk(ret).appendString(").get().");
@@ -151,13 +169,19 @@ class SourceTranspiler {
151
169
  }
152
170
  ret = new chunk_1.Chunk().appendString(new _1.TypeNameOrInfer().transpile(typ, traversal).getCode());
153
171
  ret.appendString(".set(");
154
- // todo: handle LET
155
172
  const context = new _1.TypeNameOrInfer().findType(typ, traversal);
156
- ret.appendString(new SourceTranspiler().transpile(c.getFirstChild(), traversal, context).getCode());
173
+ const convSource = c.findDirectExpression(core_1.Expressions.Source);
174
+ ret.appendString(new SourceTranspiler().transpile(convSource, traversal, context).getCode());
157
175
  ret.appendString(")");
158
176
  if (this.addGet) {
159
177
  ret.appendString(".get()");
160
178
  }
179
+ const convLet = c.findDirectExpression(core_1.Expressions.Let);
180
+ if (convLet) {
181
+ // the LET bindings are declared in a scope of their own, before the value is built
182
+ const letCode = new let_1.LetTranspiler().transpile(convLet, traversal).getCode();
183
+ ret = new chunk_1.Chunk().appendString(`(await (async () => { ${letCode} return ${ret.getCode()}; })())`);
184
+ }
161
185
  }
162
186
  else if (c.get() instanceof core_1.Expressions.ValueBody) {
163
187
  continue;
@@ -11,6 +11,7 @@ export declare class SQLCondTranspiler implements IExpressionTranspiler {
11
11
  private findSubselect;
12
12
  private sqlSubselect;
13
13
  private sqlSource;
14
+ private sqlHost;
14
15
  private basicConditionNew;
15
16
  private sourceWithComponents;
16
17
  private sqlOperator;
@@ -151,6 +151,11 @@ class SQLCondTranspiler {
151
151
  ret += fieldName + " IS NULL";
152
152
  return ret;
153
153
  }
154
+ const aggregation = c.findDirectExpression(abaplint.Expressions.SQLAggregation);
155
+ if (aggregation && operator && source) {
156
+ return aggregation.concatTokens() + " " + this.sqlOperator(operator.concatTokens()) + " "
157
+ + this.sqlSource(source, traversal, filename, table, true);
158
+ }
154
159
  if (fieldName === undefined || operator === undefined || source === undefined) {
155
160
  throw new Error("SQL Condition, transpiler todo2, " + c.concatTokens());
156
161
  }
@@ -212,17 +217,18 @@ class SQLCondTranspiler {
212
217
  }
213
218
  return ret + ")";
214
219
  }
215
- sqlSource(source, traversal, filename, table) {
220
+ sqlSource(source, traversal, filename, table, numericHost = false) {
216
221
  let ret = "";
217
222
  const simple = source.findDirectExpression(abaplint.Expressions.SimpleSource3);
218
223
  const hostExpression = source.findDirectExpression(abaplint.Expressions.Source);
219
224
  const alias = source.findDirectExpression(abaplint.Expressions.SQLAliasField);
220
225
  if (source.getFirstToken().getStr() === "@" && hostExpression) {
221
226
  const code = new source_1.SourceTranspiler(true).transpile(hostExpression, traversal).getCode();
222
- ret += "'\" + " + code + " + \"'";
227
+ ret += this.sqlHost(code, numericHost);
223
228
  }
224
229
  else if (simple && simple.findDirectExpression(abaplint.Expressions.Constant) === undefined) {
225
- ret += "'\" + " + new simple_source3_1.SimpleSource3Transpiler(true).transpile(simple, traversal).getCode() + " + \"'";
230
+ const code = new simple_source3_1.SimpleSource3Transpiler(true).transpile(simple, traversal).getCode();
231
+ ret += this.sqlHost(code, numericHost);
226
232
  }
227
233
  else if (alias) {
228
234
  // SQLAliasField might be a SQL reference or value from ABAP interface
@@ -257,6 +263,12 @@ class SQLCondTranspiler {
257
263
  }
258
264
  return ret;
259
265
  }
266
+ sqlHost(code, numericHost) {
267
+ if (numericHost) {
268
+ return `" + ((value) => typeof value === "number" || typeof value === "bigint" ? value : "'" + value + "'")(${code}) + "`;
269
+ }
270
+ return "'\" + " + code + " + \"'";
271
+ }
260
272
  basicConditionNew(node, traversal, filename, table) {
261
273
  const sourceWithComponents = this.sourceWithComponents(node, traversal);
262
274
  if (sourceWithComponents) {
@@ -30,6 +30,7 @@ class ValueBodyTranspiler {
30
30
  const outerLetCode = outerLet === undefined
31
31
  ? undefined
32
32
  : new let_1.LetTranspiler().transpile(outerLet, traversal).getCode();
33
+ let hasFor = false;
33
34
  const children = body.getChildren();
34
35
  for (let i = 0; i < children.length; i++) {
35
36
  const child = children[i];
@@ -72,6 +73,7 @@ class ValueBodyTranspiler {
72
73
  }
73
74
  }
74
75
  i = idx - 1;
76
+ hasFor = true;
75
77
  const result = this.buildForChain(forNodes, typ, traversal, body, baseCode, outerLetCode);
76
78
  ret = result.chunk;
77
79
  post = result.post;
@@ -99,14 +101,18 @@ class ValueBodyTranspiler {
99
101
  throw new Error("ValueBodyTranspiler, unknown " + child.get().constructor.name + " \"" + child.concatTokens()) + "\"";
100
102
  }
101
103
  }
102
- return ret.appendString(post);
104
+ ret.appendString(post);
105
+ if (outerLetCode !== undefined && hasFor === false) {
106
+ // without FOR the LET bindings are declared here, in a scope of their own, before the value is built
107
+ ret = new chunk_1.Chunk().appendString(`(await (async () => { ${outerLetCode} return ${ret.getCode()}; })())`);
108
+ }
109
+ return ret;
103
110
  }
104
111
  buildForChain(forNodes, typ, traversal, body, baseCode, outerLetCode) {
105
112
  const val = baseCode ?? new type_name_or_infer_1.TypeNameOrInfer().transpile(typ, traversal).getCode();
106
113
  const chunk = new chunk_1.Chunk();
107
114
  const preLoopDecls = outerLetCode === undefined ? [] : [outerLetCode];
108
115
  const descriptors = [];
109
- const levelIndents = [];
110
116
  let uniqueCounter = 1;
111
117
  for (const child of forNodes) {
112
118
  const loop = child.findDirectExpression(core_1.Expressions.InlineLoopDefinition);
@@ -222,11 +228,11 @@ class ValueBodyTranspiler {
222
228
  letCode = new let_1.LetTranspiler().transpile(llet, traversal).getCode();
223
229
  }
224
230
  const condCode = traversal.traverse(cond).getCode();
225
- const preCheck = hasWhile ? `if (!(${condCode})) {\n break;\n}` : "";
231
+ const preCheck = hasWhile ? `if (!(${condCode})) {\nbreak;\n}` : "";
226
232
  const postLoop = [];
227
233
  postLoop.push(incrementLine);
228
234
  if (hasUntil) {
229
- postLoop.push(`if (${condCode}) {\n break;\n}`);
235
+ postLoop.push(`if (${condCode}) {\nbreak;\n}`);
230
236
  }
231
237
  descriptors.push({
232
238
  beforeLoop: [declare, `${counterName}.set(${start});`],
@@ -241,34 +247,31 @@ class ValueBodyTranspiler {
241
247
  throw new Error("ValueBodyTranspiler FOR internal error");
242
248
  }
243
249
  chunk.appendString("await (async () => {\n");
244
- this.appendBlocks(chunk, preLoopDecls, "");
250
+ this.appendBlocks(chunk, preLoopDecls);
245
251
  chunk.appendString(`const VAL = ${val};\n`);
246
- let indent = "";
252
+ // no manual indentation, Chunk.runIndentationLogic indents by brace depth,
253
+ // pre-indented closing braces would not be recognized and drift the indentation
247
254
  for (const desc of descriptors) {
248
- this.appendBlocks(chunk, desc.beforeLoop, indent);
249
- chunk.appendString(indent + desc.open + "\n");
250
- indent += " ";
251
- levelIndents.push(indent);
252
- this.appendBlocks(chunk, desc.preBody, indent);
255
+ this.appendBlocks(chunk, desc.beforeLoop);
256
+ chunk.appendString(desc.open + "\n");
257
+ this.appendBlocks(chunk, desc.preBody);
253
258
  }
254
- chunk.appendString(indent + "VAL");
259
+ chunk.appendString("VAL");
255
260
  let post = ";\n";
256
261
  for (let i = descriptors.length - 1; i >= 0; i--) {
257
262
  const desc = descriptors[i];
258
- const currentIndent = levelIndents[i] ?? "";
259
- post += this.blocksToString(desc.postBody, currentIndent);
260
- const parentIndent = currentIndent.substring(0, Math.max(0, currentIndent.length - 2));
261
- post += parentIndent + desc.close + "\n";
263
+ post += this.blocksToString(desc.postBody);
264
+ post += desc.close + "\n";
262
265
  }
263
266
  post += "return VAL;\n})()";
264
267
  return { chunk, post };
265
268
  }
266
- appendBlocks(chunk, blocks, indent) {
269
+ appendBlocks(chunk, blocks) {
267
270
  for (const block of blocks) {
268
- this.appendBlock(chunk, block, indent);
271
+ this.appendBlock(chunk, block);
269
272
  }
270
273
  }
271
- appendBlock(chunk, block, indent) {
274
+ appendBlock(chunk, block) {
272
275
  if (block === "") {
273
276
  return;
274
277
  }
@@ -278,10 +281,10 @@ class ValueBodyTranspiler {
278
281
  if (clean.trim() === "") {
279
282
  continue;
280
283
  }
281
- chunk.appendString(indent + clean + "\n");
284
+ chunk.appendString(clean + "\n");
282
285
  }
283
286
  }
284
- blocksToString(blocks, indent) {
287
+ blocksToString(blocks) {
285
288
  let ret = "";
286
289
  for (const block of blocks) {
287
290
  if (block === "") {
@@ -293,7 +296,7 @@ class ValueBodyTranspiler {
293
296
  if (clean.trim() === "") {
294
297
  continue;
295
298
  }
296
- ret += indent + clean + "\n";
299
+ ret += clean + "\n";
297
300
  }
298
301
  }
299
302
  return ret;
@@ -0,0 +1,17 @@
1
+ import * as abaplint from "@abaplint/core";
2
+ import { Traversal } from "../traversal";
3
+ /** the Sources and Targets of a DATASET statement, each found by the
4
+ * keywords right in front of it: "MESSAGE" in "FOR INPUT IN BINARY MODE
5
+ * MESSAGE m", "LENGTH" only when not "MAXIMUM LENGTH" or "ACTUAL LENGTH" */
6
+ export declare class DatasetOperands {
7
+ private readonly operands;
8
+ private readonly words;
9
+ constructor(node: abaplint.Nodes.StatementNode, traversal: Traversal);
10
+ /** whether the statement has these keywords in a row: its own tokens only,
11
+ * never the text of an operand, so a variable lv_type or a literal
12
+ * 'no end of line' is not an addition */
13
+ has(words: string): boolean;
14
+ /** the dataset name, or the source of TRANSFER: the first operand */
15
+ first(): string;
16
+ after(words: string, notAfter?: string[]): string | undefined;
17
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DatasetOperands = void 0;
37
+ const abaplint = __importStar(require("@abaplint/core"));
38
+ /** the Sources and Targets of a DATASET statement, each found by the
39
+ * keywords right in front of it: "MESSAGE" in "FOR INPUT IN BINARY MODE
40
+ * MESSAGE m", "LENGTH" only when not "MAXIMUM LENGTH" or "ACTUAL LENGTH" */
41
+ class DatasetOperands {
42
+ operands = [];
43
+ words = [];
44
+ constructor(node, traversal) {
45
+ let keywords = [];
46
+ for (const c of node.getChildren()) {
47
+ if (c instanceof abaplint.Nodes.TokenNode) {
48
+ keywords.push(c.getFirstToken().getStr().toUpperCase());
49
+ this.words.push(c.getFirstToken().getStr().toUpperCase());
50
+ }
51
+ else if (c instanceof abaplint.Nodes.ExpressionNode) {
52
+ this.operands.push({ keywords, code: traversal.traverse(c).getCode() });
53
+ keywords = [];
54
+ }
55
+ }
56
+ }
57
+ /** whether the statement has these keywords in a row: its own tokens only,
58
+ * never the text of an operand, so a variable lv_type or a literal
59
+ * 'no end of line' is not an addition */
60
+ has(words) {
61
+ // abaplint splits UTF-8, NON-UNICODE and BYTE-ORDER into three tokens
62
+ const joined = this.words.join(" ").replace(/ - /g, "-");
63
+ return (" " + joined + " ").includes(" " + words + " ");
64
+ }
65
+ /** the dataset name, or the source of TRANSFER: the first operand */
66
+ first() {
67
+ return this.operands[0].code;
68
+ }
69
+ after(words, notAfter = []) {
70
+ const want = words.split(" ");
71
+ for (const o of this.operands.slice(1)) {
72
+ const tail = o.keywords.slice(-want.length);
73
+ const before = o.keywords[o.keywords.length - want.length - 1];
74
+ if (tail.join(" ") === words && (before === undefined || notAfter.includes(before) === false)) {
75
+ return o.code;
76
+ }
77
+ }
78
+ return undefined;
79
+ }
80
+ }
81
+ exports.DatasetOperands = DatasetOperands;
82
+ //# sourceMappingURL=_dataset.js.map
@@ -0,0 +1,18 @@
1
+ import * as abaplint from "@abaplint/core";
2
+ import { Traversal } from "../traversal";
3
+ /** PARAMETERS and SELECT-OPTIONS declare program variables that exist, with their
4
+ * DEFAULT values, before INITIALIZATION runs. Without LOWER CASE a character-like
5
+ * default is upper-cased (measured on a 7.5x system: 'abcdef' into a parameter of
6
+ * length 4 is "ABCD", a string parameter and the LOW of a select-option likewise) */
7
+ export declare class SelectionDefault {
8
+ static variable(node: abaplint.Nodes.StatementNode, traversal: Traversal): {
9
+ name: string;
10
+ type: abaplint.AbstractType;
11
+ } | undefined;
12
+ /** the expression after a keyword of the statement, eg. DEFAULT; only a keyword
13
+ * token counts, an operand named like the keyword does not */
14
+ static after(node: abaplint.Nodes.StatementNode, keyword: string): abaplint.Nodes.ExpressionNode | undefined;
15
+ /** sets the target to a DEFAULT operand, a Constant or a FieldChain, and upper-cases
16
+ * it when the target is character-like and the statement has no LOWER CASE */
17
+ static set(node: abaplint.Nodes.StatementNode, target: string, targetType: abaplint.AbstractType, operand: abaplint.Nodes.ExpressionNode, traversal: Traversal): string;
18
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SelectionDefault = void 0;
37
+ const abaplint = __importStar(require("@abaplint/core"));
38
+ const traversal_1 = require("../traversal");
39
+ /** PARAMETERS and SELECT-OPTIONS declare program variables that exist, with their
40
+ * DEFAULT values, before INITIALIZATION runs. Without LOWER CASE a character-like
41
+ * default is upper-cased (measured on a 7.5x system: 'abcdef' into a parameter of
42
+ * length 4 is "ABCD", a string parameter and the LOW of a select-option likewise) */
43
+ class SelectionDefault {
44
+ static variable(node, traversal) {
45
+ const token = node.findDirectExpression(abaplint.Expressions.FieldSub)?.getFirstToken();
46
+ if (token === undefined) {
47
+ return undefined;
48
+ }
49
+ const found = traversal.findCurrentScopeByToken(token)?.findVariable(token.getStr());
50
+ if (found === undefined) {
51
+ return undefined;
52
+ }
53
+ return {
54
+ name: traversal_1.Traversal.prefixVariable(traversal_1.Traversal.escapeNamespace(found.getName().toLowerCase())),
55
+ type: found.getType(),
56
+ };
57
+ }
58
+ /** the expression after a keyword of the statement, eg. DEFAULT; only a keyword
59
+ * token counts, an operand named like the keyword does not */
60
+ static after(node, keyword) {
61
+ const children = node.getChildren();
62
+ for (let i = 0; i < children.length - 1; i++) {
63
+ if (children[i] instanceof abaplint.Nodes.TokenNode && children[i].concatTokens().toUpperCase() === keyword) {
64
+ return children[i + 1];
65
+ }
66
+ }
67
+ return undefined;
68
+ }
69
+ /** sets the target to a DEFAULT operand, a Constant or a FieldChain, and upper-cases
70
+ * it when the target is character-like and the statement has no LOWER CASE */
71
+ static set(node, target, targetType, operand, traversal) {
72
+ let code = "\n" + target + ".set(" + traversal.traverse(operand).getCode() + ");";
73
+ const characterLike = targetType instanceof abaplint.BasicTypes.CharacterType
74
+ || targetType instanceof abaplint.BasicTypes.StringType;
75
+ if (node.findDirectTokenByText("LOWER") === undefined && characterLike === true) {
76
+ code += "\n" + target + ".set(abap.builtin.to_upper({val: " + target + "}));";
77
+ }
78
+ return code;
79
+ }
80
+ }
81
+ exports.SelectionDefault = SelectionDefault;
82
+ //# sourceMappingURL=_selection.js.map
@@ -43,15 +43,16 @@ class AssignTranspiler {
43
43
  if (node?.findFirstExpression(abaplint.Expressions.TableExpression) === undefined) {
44
44
  return code;
45
45
  }
46
+ // not indented, Chunk.runIndentationLogic indents by brace depth
46
47
  return `(await (async () => {
47
- try {
48
- return ${code};
49
- } catch (error) {
50
- if (abap.isLineNotFound(error)) {
51
- return undefined;
52
- }
53
- throw error;
54
- }
48
+ try {
49
+ return ${code};
50
+ } catch (error) {
51
+ if (abap.isLineNotFound(error)) {
52
+ return undefined;
53
+ }
54
+ throw error;
55
+ }
55
56
  })())`;
56
57
  }
57
58
  transpile(node, traversal) {
@@ -145,7 +145,7 @@ class CallTranspiler {
145
145
  post += `\nabap.builtin.sy.get().subrc.set(0);
146
146
  } catch (e) {
147
147
  if (e.classic) {
148
- switch (e.classic.toUpperCase()) {\n`;
148
+ switch (e.classic.toUpperCase()) {\n`;
149
149
  for (const e of node.findAllExpressions(abaplint.Expressions.ParameterException)) {
150
150
  const name = e.getFirstToken().getStr().toUpperCase();
151
151
  // todo, also handle SimpleChain,
@@ -164,9 +164,9 @@ if (e.classic) {
164
164
  post += `case "${name}": abap.builtin.sy.get().subrc.set(${value}); break;\n`;
165
165
  }
166
166
  }
167
- post += ` }
167
+ post += `}
168
168
  } else {
169
- throw e;
169
+ throw e;
170
170
  }
171
171
  }`;
172
172
  return { pre, post };
@@ -65,12 +65,13 @@ class CallFunctionTranspiler {
65
65
  }
66
66
  const calling = node.findExpressionAfterToken("CALLING");
67
67
  const dest = node.findDirectExpression(abaplint.Expressions.Destination)?.findDirectExpression(abaplint.Expressions.Source);
68
- if (dest) {
68
+ const updateTask = node.findDirectTokenByText("UPDATE") !== undefined;
69
+ if (dest && updateTask === false) {
69
70
  const s = new expressions_1.SourceTranspiler(true).transpile(dest, traversal);
70
71
  param = param.replace("{", ",").replace(/}$/, "");
71
72
  ret.appendString(`await abap.statements.callFunction({name:${fmname},destination:${s.getCode()}${param}});`);
72
73
  }
73
- else if (calling) {
74
+ else if (calling && updateTask === false) {
74
75
  param = param.replace("{", ",").replace(/}$/, "");
75
76
  // typically used in combination with STARTING NEW TASK so dont await,
76
77
  ret.appendString(`abap.statements.callFunction({name:${fmname},calling:this.${calling.concatTokens().toLowerCase()}${param}});`);
@@ -80,7 +81,13 @@ class CallFunctionTranspiler {
80
81
  const call = `abap.FunctionModules[${fmname}]`;
81
82
  // eslint-disable-next-line max-len
82
83
  ret.appendString(`if (${call} === undefined) { if (${illegalFunc} === undefined) { throw "CX_SY_DYN_CALL_ILLEGAL_FUNC not found"; } else { throw await new ${illegalFunc}().constructor_({function: new abap.types.String().set(${fmname})});} }\n`);
83
- ret.appendString(`await ${call}(${param});`);
84
+ if (updateTask) {
85
+ param = param.replace("{", ",").replace(/}$/, "");
86
+ ret.appendString(`await abap.statements.callFunction({name:${fmname},updateTask:true${param}});`);
87
+ }
88
+ else {
89
+ ret.appendString(`await ${call}(${param});`);
90
+ }
84
91
  }
85
92
  if (exceptions) {
86
93
  const build = call_1.CallTranspiler.buildExceptions(exceptions);
@@ -3,5 +3,5 @@ import { IStatementTranspiler } from "./_statement_transpiler";
3
3
  import { Traversal } from "../traversal";
4
4
  import { Chunk } from "../chunk";
5
5
  export declare class CloseDatasetTranspiler implements IStatementTranspiler {
6
- transpile(_node: abaplint.Nodes.StatementNode, _traversal: Traversal): Chunk;
6
+ transpile(node: abaplint.Nodes.StatementNode, traversal: Traversal): Chunk;
7
7
  }