@abaplint/core 2.115.25 → 2.115.27

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.
@@ -824,10 +824,43 @@ declare class CDSAnnotationSimple extends Expression {
824
824
  getRunnable(): IStatementRunnable;
825
825
  }
826
826
 
827
+ /**
828
+ * Arithmetic expression: one or more values joined by +, -, *, /.
829
+ *
830
+ * Parenthesized sub-expressions of any nesting depth are handled via the
831
+ * separate CDSArithParen singleton (which wraps back to CDSArithmetics).
832
+ * The mutual reference between two distinct singletons enables true n-level
833
+ * nesting with no fixed limit and no infinite recursion.
834
+ *
835
+ * Grammar (simplified):
836
+ * CDSArithmetics → operand (op operand)+ -- with-operator form
837
+ * | unary val -- unary form
838
+ * | unary val (op operand)+ -- unary + continuation
839
+ * | unary CDSArithParen -- unary applied to paren, e.g. -(field)
840
+ * | unary CDSArithParen (op op)+ -- unary paren + continuation
841
+ * operand → CDSArithParen | val
842
+ * CDSArithParen → "(" CDSArithmetics ")" | "(" CDSArithParen ")" | "(" val ")"
843
+ */
827
844
  declare class CDSArithmetics extends Expression {
828
845
  getRunnable(): IStatementRunnable;
829
846
  }
830
847
 
848
+ /**
849
+ * Parenthesized arithmetic sub-expression.
850
+ *
851
+ * Matches either:
852
+ * "(" CDSArithmetics ")" — parenthesized expression with operators, e.g. (A + B), (A - B * C)
853
+ * "(" CDSArithParen ")" — nested grouping parens, e.g. ((A + B)), (((A + B)))
854
+ * "(" val ")" — parenthesized single value used for grouping, e.g. (field), (func(...))
855
+ *
856
+ * Mutual recursion with CDSArithmetics enables n-level deep nesting with no fixed limit:
857
+ * CDSArithmetics → operand (op operand)+
858
+ * CDSArithParen → "(" CDSArithmetics ")" | "(" CDSArithParen ")" | "(" val ")"
859
+ */
860
+ declare class CDSArithParen extends Expression {
861
+ getRunnable(): IStatementRunnable;
862
+ }
863
+
831
864
  declare class CDSAs extends Expression {
832
865
  getRunnable(): IStatementRunnable;
833
866
  }
@@ -864,6 +897,10 @@ declare class CDSDefineCustom extends Expression {
864
897
  getRunnable(): IStatementRunnable;
865
898
  }
866
899
 
900
+ declare class CDSDefineHierarchy extends Expression {
901
+ getRunnable(): IStatementRunnable;
902
+ }
903
+
867
904
  declare class CDSDefineProjection extends Expression {
868
905
  getRunnable(): IStatementRunnable;
869
906
  }
@@ -2555,6 +2592,7 @@ declare namespace ExpressionsCDS {
2555
2592
  CDSAnnotationObject,
2556
2593
  CDSAnnotationSimple,
2557
2594
  CDSAnnotation,
2595
+ CDSArithParen,
2558
2596
  CDSArithmetics,
2559
2597
  CDSAs,
2560
2598
  CDSAssociation,
@@ -2565,6 +2603,7 @@ declare namespace ExpressionsCDS {
2565
2603
  CDSCondition,
2566
2604
  CDSDefineAbstract,
2567
2605
  CDSDefineCustom,
2606
+ CDSDefineHierarchy,
2568
2607
  CDSDefineProjection,
2569
2608
  CDSDefineTableFunction,
2570
2609
  CDSDefineView,
@@ -245,7 +245,7 @@ class Select {
245
245
  }
246
246
  }
247
247
  static buildStructureType(fields, dbSources, scope) {
248
- var _a, _b, _c;
248
+ var _a, _b, _c, _d, _e, _f;
249
249
  if (fields.length === 1 && dbSources.length === 1) {
250
250
  const dbType = (_a = dbSources[0]) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
251
251
  if (dbType === undefined) {
@@ -286,8 +286,36 @@ class Select {
286
286
  }
287
287
  }
288
288
  }
289
+ else if (dbSources.length === 1) {
290
+ const dbType = (_d = dbSources[0]) === null || _d === void 0 ? void 0 : _d.parseType(scope.getRegistry());
291
+ if (dbType === undefined) {
292
+ const name = ((_e = dbSources[0]) === null || _e === void 0 ? void 0 : _e.getName()) || "buildStructureTypeError";
293
+ if (scope.getRegistry().inErrorNamespace(name) === true) {
294
+ return new basic_1.UnknownType("Select, " + name + " not found");
295
+ }
296
+ else {
297
+ return basic_1.VoidType.get((_f = dbSources[0]) === null || _f === void 0 ? void 0 : _f.getName());
298
+ }
299
+ }
300
+ if (!(dbType instanceof basic_1.StructureType)) {
301
+ return basic_1.VoidType.get("SELECT_todo14");
302
+ }
303
+ const allFieldsSimple = fields.every(f => isSimple.test(f.code));
304
+ if (allFieldsSimple === true) {
305
+ const components = [];
306
+ for (const field of fields) {
307
+ const type = dbType.getComponentByName(field.code);
308
+ if (type === undefined) {
309
+ return basic_1.VoidType.get("SELECT_todo9");
310
+ }
311
+ components.push({ name: field.as || field.code, type });
312
+ }
313
+ return new basic_1.StructureType(components);
314
+ }
315
+ return basic_1.VoidType.get("SELECT_todo12");
316
+ }
289
317
  else {
290
- return basic_1.VoidType.get("SELECT_todo9");
318
+ return basic_1.VoidType.get("SELECT_todo13");
291
319
  }
292
320
  }
293
321
  static buildTableType(fields, dbSources, scope) {
@@ -117,10 +117,12 @@ class CDSLexer {
117
117
  }
118
118
  switch (next) {
119
119
  case "'":
120
+ build = result.add(build, row, col, mode);
120
121
  mode = Mode.String;
121
122
  build += next;
122
123
  break;
123
124
  case " ":
125
+ case "\t":
124
126
  build = result.add(build, row, col, mode);
125
127
  break;
126
128
  case "\n":
@@ -148,6 +150,11 @@ class CDSLexer {
148
150
  build = result.add(build, row, col, mode);
149
151
  result.add(next, row, col, mode);
150
152
  break;
153
+ case "@":
154
+ // @ starts a new annotation; flush current token and start building with @
155
+ build = result.add(build, row, col, mode);
156
+ build = "@";
157
+ break;
151
158
  default:
152
159
  build += next;
153
160
  break;
@@ -34,6 +34,9 @@ class CDSParser {
34
34
  if (res === undefined || !(res[0] instanceof nodes_1.ExpressionNode)) {
35
35
  res = combi_1.Combi.run(new Expressions.CDSExtendView(), tokens, version_1.defaultVersion);
36
36
  }
37
+ if (res === undefined || !(res[0] instanceof nodes_1.ExpressionNode)) {
38
+ res = combi_1.Combi.run(new Expressions.CDSDefineHierarchy(), tokens, version_1.defaultVersion);
39
+ }
37
40
  if (res === undefined || !(res[0] instanceof nodes_1.ExpressionNode)) {
38
41
  return undefined;
39
42
  }
@@ -5,7 +5,7 @@ const _1 = require(".");
5
5
  const combi_1 = require("../../abap/2_statements/combi");
6
6
  class CDSAnnotationSimple extends combi_1.Expression {
7
7
  getRunnable() {
8
- const value = (0, combi_1.alt)(_1.CDSString, "true", "false", (0, combi_1.regex)(/^\d+$/), (0, combi_1.seq)((0, combi_1.regex)(/^\d+$/), ".", (0, combi_1.regex)(/^\d+$/)), (0, combi_1.seq)("#", "(", (0, combi_1.regex)(/^[\w_]+$/), ")"), (0, combi_1.regex)(/^#[\w_]+$/));
8
+ const value = (0, combi_1.alt)(_1.CDSString, "true", "false", "null", (0, combi_1.seq)("-", (0, combi_1.regex)(/^\d+$/)), (0, combi_1.regex)(/^\d+$/), (0, combi_1.seq)((0, combi_1.regex)(/^\d+$/), ".", (0, combi_1.regex)(/^\d+$/)), (0, combi_1.seq)("#", "(", _1.CDSString, ")"), (0, combi_1.seq)("#", "(", (0, combi_1.regex)(/^[\w_]+$/), ")"), (0, combi_1.regex)(/^#[\w_]+$/));
9
9
  return value;
10
10
  }
11
11
  }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CDSArithParen = void 0;
4
+ const _1 = require(".");
5
+ const combi_1 = require("../../abap/2_statements/combi");
6
+ const cds_integer_1 = require("./cds_integer");
7
+ /**
8
+ * Parenthesized arithmetic sub-expression.
9
+ *
10
+ * Matches either:
11
+ * "(" CDSArithmetics ")" — parenthesized expression with operators, e.g. (A + B), (A - B * C)
12
+ * "(" CDSArithParen ")" — nested grouping parens, e.g. ((A + B)), (((A + B)))
13
+ * "(" val ")" — parenthesized single value used for grouping, e.g. (field), (func(...))
14
+ *
15
+ * Mutual recursion with CDSArithmetics enables n-level deep nesting with no fixed limit:
16
+ * CDSArithmetics → operand (op operand)+
17
+ * CDSArithParen → "(" CDSArithmetics ")" | "(" CDSArithParen ")" | "(" val ")"
18
+ */
19
+ class CDSArithParen extends combi_1.Expression {
20
+ getRunnable() {
21
+ const val = (0, combi_1.altPrio)(cds_integer_1.CDSInteger, _1.CDSFunction, _1.CDSCase, _1.CDSCast, _1.CDSString, _1.CDSAggregate, _1.CDSPrefixedName);
22
+ return (0, combi_1.seq)("(", (0, combi_1.altPrio)(_1.CDSArithmetics, CDSArithParen, val), ")");
23
+ }
24
+ }
25
+ exports.CDSArithParen = CDSArithParen;
26
+ //# sourceMappingURL=cds_arith_paren.js.map
@@ -4,19 +4,50 @@ exports.CDSArithmetics = void 0;
4
4
  const _1 = require(".");
5
5
  const combi_1 = require("../../abap/2_statements/combi");
6
6
  const cds_integer_1 = require("./cds_integer");
7
+ /**
8
+ * Arithmetic expression: one or more values joined by +, -, *, /.
9
+ *
10
+ * Parenthesized sub-expressions of any nesting depth are handled via the
11
+ * separate CDSArithParen singleton (which wraps back to CDSArithmetics).
12
+ * The mutual reference between two distinct singletons enables true n-level
13
+ * nesting with no fixed limit and no infinite recursion.
14
+ *
15
+ * Grammar (simplified):
16
+ * CDSArithmetics → operand (op operand)+ -- with-operator form
17
+ * | unary val -- unary form
18
+ * | unary val (op operand)+ -- unary + continuation
19
+ * | unary CDSArithParen -- unary applied to paren, e.g. -(field)
20
+ * | unary CDSArithParen (op op)+ -- unary paren + continuation
21
+ * operand → CDSArithParen | val
22
+ * CDSArithParen → "(" CDSArithmetics ")" | "(" CDSArithParen ")" | "(" val ")"
23
+ */
7
24
  class CDSArithmetics extends combi_1.Expression {
8
25
  getRunnable() {
9
- const name = (0, combi_1.seq)(_1.CDSName, (0, combi_1.optPrio)((0, combi_1.seq)(".", _1.CDSName)));
10
- const val = (0, combi_1.altPrio)(cds_integer_1.CDSInteger, _1.CDSFunction, _1.CDSCase, _1.CDSCast, _1.CDSString, _1.CDSAggregate, name);
26
+ const val = (0, combi_1.altPrio)(cds_integer_1.CDSInteger, _1.CDSFunction, _1.CDSCase, _1.CDSCast, _1.CDSString, _1.CDSAggregate, _1.CDSPrefixedName);
11
27
  const operator = (0, combi_1.altPrio)("+", "-", "*", "/");
12
- // Support unary operators (e.g., "- field" in CASE expressions)
28
+ // Unary operator prefix, e.g. -field, +field
13
29
  const unary = (0, combi_1.altPrio)("-", "+");
14
30
  const unaryExpression = (0, combi_1.seq)(unary, val);
15
- const operatorValue = (0, combi_1.seq)(operator, val);
16
- const paren = (0, combi_1.seq)("(", val, (0, combi_1.plusPrio)(operatorValue), ")");
17
- const noParen = (0, combi_1.seq)(val, (0, combi_1.plusPrio)(operatorValue));
18
- // todo: this is pretty bad, it needs a rewrite
19
- return (0, combi_1.altPrio)(unaryExpression, (0, combi_1.seq)(paren, (0, combi_1.starPrio)(operatorValue)), noParen);
31
+ // An operand is either a parenthesized sub-expression (any depth) or a bare value.
32
+ // CDSArithParen = "(" altPrio(CDSArithmetics, CDSArithParen, val) ")" — separate singleton that
33
+ // can recursively contain itself, enabling deeply nested parentheses without infinite recursion.
34
+ const operand = (0, combi_1.altPrio)(_1.CDSArithParen, val);
35
+ const operatorValue = (0, combi_1.seq)(operator, operand);
36
+ // Main form: operand op operand op ... (leading term may itself be a paren)
37
+ const withOperators = (0, combi_1.seq)(operand, (0, combi_1.plusPrio)(operatorValue));
38
+ // Unary followed by optional continuation operators: -1 * field, -field + 1
39
+ const unaryWithOps = (0, combi_1.seq)(unaryExpression, (0, combi_1.plusPrio)(operatorValue));
40
+ // Top-level parenthesized expression as a standalone field value: (A + B) * C
41
+ const parenExpr = (0, combi_1.altPrio)(withOperators, unaryExpression);
42
+ const paren = (0, combi_1.seq)("(", parenExpr, ")");
43
+ // Unary applied to a parenthesized group, e.g. -(TaxAmount)
44
+ const unaryParen = (0, combi_1.seq)(unary, _1.CDSArithParen);
45
+ return (0, combi_1.altPrio)((0, combi_1.seq)(paren, (0, combi_1.starPrio)(operatorValue)), // (expr) op ...
46
+ (0, combi_1.seq)(unaryParen, (0, combi_1.starPrio)(operatorValue)), // -(paren) op ...
47
+ unaryWithOps, // -val op ...
48
+ unaryExpression, // -val
49
+ unaryParen, // -(paren)
50
+ withOperators);
20
51
  }
21
52
  }
22
53
  exports.CDSArithmetics = CDSArithmetics;
@@ -6,7 +6,7 @@ const combi_1 = require("../../abap/2_statements/combi");
6
6
  const cds_cardinality_1 = require("./cds_cardinality");
7
7
  class CDSAssociation extends combi_1.Expression {
8
8
  getRunnable() {
9
- return (0, combi_1.seq)("ASSOCIATION", (0, combi_1.opt)(cds_cardinality_1.CDSCardinality), "TO", (0, combi_1.opt)("PARENT"), _1.CDSRelation, "ON", _1.CDSCondition);
9
+ return (0, combi_1.seq)("ASSOCIATION", (0, combi_1.opt)(cds_cardinality_1.CDSCardinality), "TO", (0, combi_1.opt)("PARENT"), _1.CDSRelation, "ON", _1.CDSCondition, (0, combi_1.opt)((0, combi_1.seq)("WITH", "DEFAULT", "FILTER", _1.CDSCondition)));
10
10
  }
11
11
  }
12
12
  exports.CDSAssociation = CDSAssociation;
@@ -5,11 +5,10 @@ const _1 = require(".");
5
5
  const combi_1 = require("../../abap/2_statements/combi");
6
6
  class CDSCase extends combi_1.Expression {
7
7
  getRunnable() {
8
- const name = (0, combi_1.seq)(_1.CDSName, (0, combi_1.starPrio)((0, combi_1.seq)(".", _1.CDSName)));
9
- const value = (0, combi_1.altPrio)(_1.CDSString, CDSCase, _1.CDSCast, _1.CDSArithmetics, _1.CDSFunction, name);
10
- const thenValue = (0, combi_1.altPrio)((0, combi_1.seq)("(", value, ")"), value);
11
- const simple = (0, combi_1.seq)((0, combi_1.altPrio)(_1.CDSFunction, name), (0, combi_1.plusPrio)((0, combi_1.seq)("WHEN", value, "THEN", thenValue)));
12
- const complex = (0, combi_1.plusPrio)((0, combi_1.seq)("WHEN", _1.CDSCondition, "THEN", thenValue));
8
+ // CDSArithmetics first: handles cast()*n, sum()*n, field+n, etc. before standalone alternatives
9
+ const value = (0, combi_1.altPrio)(_1.CDSString, CDSCase, _1.CDSArithmetics, _1.CDSCast, _1.CDSAggregate, _1.CDSArithParen, _1.CDSFunction, _1.CDSInteger, _1.CDSPrefixedName);
10
+ const simple = (0, combi_1.seq)((0, combi_1.altPrio)(_1.CDSArithmetics, _1.CDSArithParen, _1.CDSFunction, _1.CDSPrefixedName), (0, combi_1.plusPrio)((0, combi_1.seq)("WHEN", value, "THEN", value)));
11
+ const complex = (0, combi_1.plusPrio)((0, combi_1.seq)("WHEN", _1.CDSCondition, "THEN", value));
13
12
  return (0, combi_1.seq)("CASE", (0, combi_1.altPrio)(complex, simple), (0, combi_1.optPrio)((0, combi_1.seq)("ELSE", value)), "END");
14
13
  }
15
14
  }
@@ -5,8 +5,8 @@ const _1 = require(".");
5
5
  const combi_1 = require("../../abap/2_statements/combi");
6
6
  class CDSCast extends combi_1.Expression {
7
7
  getRunnable() {
8
- const name = (0, combi_1.seq)(_1.CDSName, (0, combi_1.starPrio)((0, combi_1.seq)(".", _1.CDSName)));
9
- const first = (0, combi_1.altPrio)(_1.CDSFunction, _1.CDSCase, _1.CDSAggregate, _1.CDSArithmetics, CDSCast, _1.CDSString, _1.CDSInteger, name);
8
+ // CDSArithmetics before CDSFunction/CDSAggregate: handles function()*n, cast()*n, sum()*n patterns
9
+ const first = (0, combi_1.altPrio)(_1.CDSArithmetics, _1.CDSFunction, _1.CDSArithParen, _1.CDSCase, _1.CDSAggregate, CDSCast, _1.CDSString, _1.CDSPrefixedName, _1.CDSInteger);
10
10
  return (0, combi_1.seq)("CAST", "(", first, "AS", _1.CDSType, (0, combi_1.optPrio)((0, combi_1.seq)("PRESERVING", "TYPE")), ")");
11
11
  }
12
12
  }
@@ -6,15 +6,17 @@ const combi_1 = require("../../abap/2_statements/combi");
6
6
  const cds_integer_1 = require("./cds_integer");
7
7
  class CDSCondition extends combi_1.Expression {
8
8
  getRunnable() {
9
- const name = (0, combi_1.seq)(_1.CDSName, (0, combi_1.starPrio)((0, combi_1.seq)(".", (0, combi_1.altPrio)(_1.CDSString, _1.CDSName))));
10
- const left = (0, combi_1.altPrio)(_1.CDSString, _1.CDSFunction, _1.CDSAggregate, name);
9
+ const left = (0, combi_1.altPrio)(_1.CDSString, _1.CDSFunction, _1.CDSAggregate, _1.CDSPrefixedName);
11
10
  const operators = (0, combi_1.altPrio)("=", (0, combi_1.seq)("!", "="), (0, combi_1.seq)("<", ">"), (0, combi_1.seq)(">", "="), (0, combi_1.seq)("<", "="), "<", ">", "LIKE", "NOT LIKE");
12
- const compare = (0, combi_1.seq)(operators, (0, combi_1.altPrio)(left, cds_integer_1.CDSInteger));
11
+ // Right side of comparison: arithmetic expressions, parenthesized sub-expressions, or simple values
12
+ const right = (0, combi_1.altPrio)(_1.CDSArithmetics, _1.CDSArithParen, left, cds_integer_1.CDSInteger);
13
+ const compare = (0, combi_1.seq)(operators, right);
13
14
  const is = (0, combi_1.seq)("IS", (0, combi_1.optPrio)("NOT"), (0, combi_1.altPrio)("INITIAL", "NULL"));
14
15
  const between = (0, combi_1.seq)("BETWEEN", left, "AND", left);
15
16
  const condition = (0, combi_1.seq)((0, combi_1.optPrio)("NOT"), left, (0, combi_1.altPrio)(compare, is, between));
16
17
  const paren = (0, combi_1.seq)("(", CDSCondition, ")");
17
- return (0, combi_1.seq)((0, combi_1.altPrio)(condition, paren), (0, combi_1.starPrio)((0, combi_1.seq)((0, combi_1.altPrio)("AND", "OR"), (0, combi_1.altPrio)(condition, paren))));
18
+ const notParen = (0, combi_1.seq)("NOT", paren);
19
+ return (0, combi_1.seq)((0, combi_1.altPrio)(condition, notParen, paren), (0, combi_1.starPrio)((0, combi_1.seq)((0, combi_1.altPrio)("AND", "OR"), (0, combi_1.altPrio)(condition, notParen, paren))));
18
20
  }
19
21
  }
20
22
  exports.CDSCondition = CDSCondition;
@@ -7,7 +7,8 @@ const cds_name_1 = require("./cds_name");
7
7
  class CDSDefineAbstract extends combi_1.Expression {
8
8
  getRunnable() {
9
9
  const field = (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)((0, combi_1.str)("KEY")), cds_name_1.CDSName, ":", _1.CDSType, ";");
10
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.str)("DEFINE ABSTRACT ENTITY"), cds_name_1.CDSName, (0, combi_1.str)("{"), (0, combi_1.plus)(field), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
10
+ const compsiOrAssoci = (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), cds_name_1.CDSName, ":", (0, combi_1.alt)(_1.CDSComposition, _1.CDSAssociation), ";");
11
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), "ABSTRACT", "ENTITY", cds_name_1.CDSName, (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.alt)(field, compsiOrAssoci)), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
11
12
  }
12
13
  }
13
14
  exports.CDSDefineAbstract = CDSDefineAbstract;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CDSDefineHierarchy = void 0;
4
+ const _1 = require(".");
5
+ const combi_1 = require("../../abap/2_statements/combi");
6
+ class CDSDefineHierarchy extends combi_1.Expression {
7
+ getRunnable() {
8
+ const field = (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("KEY"), _1.CDSPrefixedName, (0, combi_1.opt)(_1.CDSAs));
9
+ const sortDirection = (0, combi_1.altPrio)("ASCENDING", "DESCENDING");
10
+ const siblingsOrderField = (0, combi_1.seq)(_1.CDSPrefixedName, (0, combi_1.opt)(sortDirection));
11
+ const siblingsOrder = (0, combi_1.seq)("SIBLINGS", "ORDER", "BY", siblingsOrderField, (0, combi_1.star)((0, combi_1.seq)(",", siblingsOrderField)));
12
+ const directory = (0, combi_1.seq)("DIRECTORY", _1.CDSName, "FILTER", "BY", _1.CDSCondition);
13
+ const hierarchyBody = (0, combi_1.seq)("SOURCE", _1.CDSName, (0, combi_1.opt)(_1.CDSParametersSelect), "CHILD", "TO", "PARENT", "ASSOCIATION", _1.CDSName, (0, combi_1.opt)(directory), (0, combi_1.opt)((0, combi_1.seq)("START", "WHERE", _1.CDSCondition)), (0, combi_1.opt)(siblingsOrder), (0, combi_1.opt)((0, combi_1.seq)("NODETYPE", _1.CDSName)), (0, combi_1.opt)((0, combi_1.seq)("MULTIPLE", "PARENTS", "ALLOWED")), (0, combi_1.opt)((0, combi_1.seq)("ORPHANS", (0, combi_1.altPrio)("IGNORE", "ROOT"))), (0, combi_1.opt)((0, combi_1.seq)("CYCLES", "BREAKUP")), (0, combi_1.opt)((0, combi_1.seq)("CACHE", (0, combi_1.altPrio)("FORCE", "NONE", "EMPTY"))));
14
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", "HIERARCHY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), "AS", "PARENT", "CHILD", "HIERARCHY", "(", hierarchyBody, ")", "{", (0, combi_1.seq)(field, (0, combi_1.star)((0, combi_1.seq)(",", field))), "}", (0, combi_1.opt)(";"));
15
+ }
16
+ }
17
+ exports.CDSDefineHierarchy = CDSDefineHierarchy;
18
+ //# sourceMappingURL=cds_define_hierarchy.js.map
@@ -9,7 +9,8 @@ const cds_select_1 = require("./cds_select");
9
9
  const cds_with_parameters_1 = require("./cds_with_parameters");
10
10
  class CDSDefineView extends combi_1.Expression {
11
11
  getRunnable() {
12
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), "VIEW", (0, combi_1.ver)(__1.Version.v755, (0, combi_1.opt)("ENTITY")), cds_name_1.CDSName, (0, combi_1.opt)(cds_with_parameters_1.CDSWithParameters), "AS", cds_select_1.CDSSelect, (0, combi_1.opt)(";"));
12
+ const columnAlias = (0, combi_1.seq)("(", cds_name_1.CDSName, (0, combi_1.star)((0, combi_1.seq)(",", cds_name_1.CDSName)), ")");
13
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), "VIEW", (0, combi_1.ver)(__1.Version.v755, (0, combi_1.opt)("ENTITY")), cds_name_1.CDSName, (0, combi_1.opt)(columnAlias), (0, combi_1.opt)(cds_with_parameters_1.CDSWithParameters), "AS", cds_select_1.CDSSelect, (0, combi_1.opt)(";"));
13
14
  }
14
15
  }
15
16
  exports.CDSDefineView = CDSDefineView;
@@ -9,7 +9,9 @@ class CDSElement extends combi_1.Expression {
9
9
  getRunnable() {
10
10
  const redirected = (0, combi_1.seq)(": REDIRECTED TO", (0, combi_1.optPrio)((0, combi_1.altPrio)("PARENT", "COMPOSITION CHILD")), _1.CDSName);
11
11
  const colonThing = (0, combi_1.seq)(":", (0, combi_1.alt)(_1.CDSName, _1.CDSType, "LOCALIZED"));
12
- return (0, combi_1.seq)((0, combi_1.starPrio)(_1.CDSAnnotation), (0, combi_1.optPrio)((0, combi_1.altPrio)("KEY", "VIRTUAL")), (0, combi_1.altPrio)(_1.CDSAggregate, _1.CDSString, _1.CDSArithmetics, _1.CDSFunction, cds_cast_1.CDSCast, _1.CDSCase, (0, combi_1.seq)("(", _1.CDSCase, ")"), (0, combi_1.seq)(_1.CDSPrefixedName, (0, combi_1.optPrio)(cds_as_1.CDSAs), (0, combi_1.optPrio)((0, combi_1.altPrio)(redirected, colonThing))), _1.CDSInteger), (0, combi_1.optPrio)(cds_as_1.CDSAs));
12
+ // $extension.* extension field wildcard
13
+ const extensionWildcard = (0, combi_1.seq)("$extension", ".", "*");
14
+ return (0, combi_1.seq)((0, combi_1.starPrio)(_1.CDSAnnotation), (0, combi_1.opt)((0, combi_1.altPrio)("KEY", "VIRTUAL")), (0, combi_1.altPrio)(extensionWildcard, _1.CDSArithmetics, _1.CDSAggregate, _1.CDSString, _1.CDSArithParen, _1.CDSFunction, cds_cast_1.CDSCast, _1.CDSCase, (0, combi_1.seq)("(", _1.CDSCase, ")"), (0, combi_1.seq)(_1.CDSPrefixedName, (0, combi_1.optPrio)(cds_as_1.CDSAs), (0, combi_1.optPrio)((0, combi_1.altPrio)(redirected, colonThing))), _1.CDSInteger), (0, combi_1.optPrio)(cds_as_1.CDSAs));
13
15
  }
14
16
  }
15
17
  exports.CDSElement = CDSElement;
@@ -43,12 +43,13 @@ class CDSFunction extends combi_1.Expression {
43
43
  const rtrim = (0, combi_1.seq)("RTRIM", "(", _1.CDSFunctionInput, ",", _1.CDSFunctionInput, ")");
44
44
  const left = (0, combi_1.seq)("LEFT", "(", _1.CDSFunctionInput, ",", _1.CDSFunctionInput, ")");
45
45
  const right = (0, combi_1.seq)("RIGHT", "(", _1.CDSFunctionInput, ",", _1.CDSFunctionInput, ")");
46
+ const fltp_to_dec = (0, combi_1.seq)("FLTP_TO_DEC", "(", _1.CDSFunctionInput, "AS", _1.CDSType, ")");
46
47
  const conversionInput = (0, combi_1.seq)(_1.CDSName, "=", ">", _1.CDSFunctionInput);
47
48
  const conversionInputs = (0, combi_1.seq)(conversionInput, (0, combi_1.starPrio)((0, combi_1.seq)(",", conversionInput)));
48
49
  const unitConversion = (0, combi_1.seq)("UNIT_CONVERSION", "(", conversionInputs, ")");
49
50
  const currencyConversion = (0, combi_1.seq)("CURRENCY_CONVERSION", "(", conversionInputs, ")");
50
51
  const decimalShift = (0, combi_1.seq)("DECIMAL_SHIFT", "(", conversionInputs, ")");
51
- return (0, combi_1.altPrio)(substring, coalesce, tstmp_to_dats, concat, tstmp_to_tims, upper, lower, abs, ceil, floor, round, div, division, concat_with_space, dats_is_valid, dats_days_between, tstmp_add_seconds, tstmp_seconds_between, tstmp_current_utctimestamp, tstmp_is_valid, abap_system_timezone, abap_user_timezone, bintohex, hextobin, dats_add_days, dats_add_months, tstmp_to_dst, dats_tims_to_tstmp, mod, left, right, lpad, rpad, instr, length, ltrim, rtrim, replace, unitConversion, currencyConversion, decimalShift);
52
+ return (0, combi_1.altPrio)(substring, coalesce, tstmp_to_dats, concat, tstmp_to_tims, upper, lower, abs, ceil, floor, round, div, division, concat_with_space, dats_is_valid, dats_days_between, tstmp_add_seconds, tstmp_seconds_between, tstmp_current_utctimestamp, tstmp_is_valid, abap_system_timezone, abap_user_timezone, bintohex, hextobin, dats_add_days, dats_add_months, tstmp_to_dst, dats_tims_to_tstmp, mod, left, right, lpad, rpad, instr, length, ltrim, rtrim, replace, unitConversion, currencyConversion, decimalShift, fltp_to_dec);
52
53
  }
53
54
  }
54
55
  exports.CDSFunction = CDSFunction;
@@ -5,8 +5,7 @@ const _1 = require(".");
5
5
  const combi_1 = require("../../abap/2_statements/combi");
6
6
  class CDSFunctionInput extends combi_1.Expression {
7
7
  getRunnable() {
8
- const qualified = (0, combi_1.seq)(_1.CDSName, (0, combi_1.opt)(_1.CDSParameters), (0, combi_1.starPrio)((0, combi_1.seq)(".", _1.CDSName, (0, combi_1.opt)(_1.CDSParameters))));
9
- const input = (0, combi_1.altPrio)(_1.CDSArithmetics, _1.CDSAggregate, _1.CDSCast, _1.CDSFunction, _1.CDSCase, _1.CDSString, qualified, _1.CDSInteger);
8
+ const input = (0, combi_1.altPrio)(_1.CDSArithmetics, _1.CDSArithParen, _1.CDSAggregate, _1.CDSCast, _1.CDSFunction, _1.CDSCase, _1.CDSString, _1.CDSPrefixedName, _1.CDSInteger);
10
9
  return input;
11
10
  }
12
11
  }
@@ -5,8 +5,7 @@ const _1 = require(".");
5
5
  const combi_1 = require("../../abap/2_statements/combi");
6
6
  class CDSGroupBy extends combi_1.Expression {
7
7
  getRunnable() {
8
- const name = (0, combi_1.seq)(_1.CDSName, (0, combi_1.star)((0, combi_1.seq)(".", _1.CDSName)));
9
- return (0, combi_1.seq)("GROUP BY", name, (0, combi_1.star)((0, combi_1.seq)(",", name)));
8
+ return (0, combi_1.seq)("GROUP BY", _1.CDSPrefixedName, (0, combi_1.star)((0, combi_1.seq)(",", _1.CDSPrefixedName)));
10
9
  }
11
10
  }
12
11
  exports.CDSGroupBy = CDSGroupBy;
@@ -4,7 +4,10 @@ exports.CDSInteger = void 0;
4
4
  const combi_1 = require("../../abap/2_statements/combi");
5
5
  class CDSInteger extends combi_1.Expression {
6
6
  getRunnable() {
7
- return (0, combi_1.seq)((0, combi_1.opt)("-"), (0, combi_1.regex)(/^\d+$/));
7
+ const digits = (0, combi_1.regex)(/^\d+$/);
8
+ // Decimal numbers like 100.00 are lexed as 3 tokens: "100" "." "00"
9
+ const decimal = (0, combi_1.seq)(digits, ".", digits);
10
+ return (0, combi_1.seq)((0, combi_1.opt)("-"), (0, combi_1.altPrio)(decimal, digits));
8
11
  }
9
12
  }
10
13
  exports.CDSInteger = CDSInteger;
@@ -6,9 +6,13 @@ const combi_1 = require("../../abap/2_statements/combi");
6
6
  const cds_condition_1 = require("./cds_condition");
7
7
  class CDSJoin extends combi_1.Expression {
8
8
  getRunnable() {
9
+ const joinTypes = (0, combi_1.optPrio)((0, combi_1.altPrio)("LEFT OUTER MANY TO EXACT ONE", "LEFT OUTER ONE TO EXACT ONE", "LEFT OUTER ONE TO MANY", "LEFT OUTER TO ONE", "LEFT OUTER TO MANY", "LEFT OUTER", "INNER ONE TO MANY", "INNER MANY TO ONE", "INNER ONE TO EXACT ONE", "INNER MANY TO EXACT ONE", "INNER", "CROSS", "RIGHT OUTER"));
9
10
  const cond = (0, combi_1.seq)(_1.CDSSource, "ON", cds_condition_1.CDSCondition);
10
11
  const foo = (0, combi_1.altPrio)((0, combi_1.seq)("(", cond, ")"), cond);
11
- return (0, combi_1.seq)((0, combi_1.optPrio)((0, combi_1.altPrio)("LEFT OUTER TO ONE", "LEFT OUTER", "INNER", "CROSS", "RIGHT OUTER")), "JOIN", (0, combi_1.altPrio)(foo, _1.CDSSource));
12
+ // Parenthesized join sub-expression: JOIN (src innerJOIN src ON cond) ON outerCond
13
+ const innerJoin = (0, combi_1.seq)(joinTypes, "JOIN", (0, combi_1.altPrio)((0, combi_1.seq)("(", cond, ")"), cond));
14
+ const parenJoinChain = (0, combi_1.seq)("(", _1.CDSSource, (0, combi_1.star)(innerJoin), ")", "ON", cds_condition_1.CDSCondition);
15
+ return (0, combi_1.seq)(joinTypes, "JOIN", (0, combi_1.altPrio)(parenJoinChain, foo, _1.CDSSource));
12
16
  }
13
17
  }
14
18
  exports.CDSJoin = CDSJoin;
@@ -6,7 +6,7 @@ const combi_1 = require("../../abap/2_statements/combi");
6
6
  class CDSParametersSelect extends combi_1.Expression {
7
7
  getRunnable() {
8
8
  const name = (0, combi_1.seq)(_1.CDSName, (0, combi_1.opt)((0, combi_1.seq)(".", _1.CDSName)));
9
- const value = (0, combi_1.alt)(name, _1.CDSString);
9
+ const value = (0, combi_1.alt)(_1.CDSInteger, name, _1.CDSString);
10
10
  const nameValue = (0, combi_1.seq)(name, ":", value);
11
11
  return (0, combi_1.seq)("(", nameValue, (0, combi_1.star)((0, combi_1.seq)(",", nameValue)), ")");
12
12
  }
@@ -5,9 +5,27 @@ const combi_1 = require("../../abap/2_statements/combi");
5
5
  const cds_name_1 = require("./cds_name");
6
6
  const cds_parameters_1 = require("./cds_parameters");
7
7
  const cds_parameters_select_1 = require("./cds_parameters_select");
8
+ const cds_condition_1 = require("./cds_condition");
9
+ const cds_integer_1 = require("./cds_integer");
10
+ const cds_string_1 = require("./cds_string");
8
11
  class CDSPrefixedName extends combi_1.Expression {
9
12
  getRunnable() {
10
- return (0, combi_1.seq)(cds_name_1.CDSName, (0, combi_1.opt)((0, combi_1.alt)(cds_parameters_1.CDSParameters, cds_parameters_select_1.CDSParametersSelect)), (0, combi_1.star)((0, combi_1.seq)(".", cds_name_1.CDSName, (0, combi_1.opt)(cds_parameters_1.CDSParameters))));
13
+ // Path filter variants:
14
+ // [inner], [left outer], [cross] — join-type redirect
15
+ // [1:left outer], [1:inner] — cardinality + join-type
16
+ // [1: condition] — cardinality + filter condition
17
+ // [condition] — filter condition only
18
+ const joinType = (0, combi_1.altPrio)("LEFT OUTER", "INNER", "CROSS");
19
+ const joinRedirect = (0, combi_1.seq)("[", joinType, "]");
20
+ const cardinalityJoin = (0, combi_1.seq)("[", cds_integer_1.CDSInteger, ":", joinType, "]");
21
+ // [1: left outer where (condition)] — cardinality + join-type + WHERE filter
22
+ const cardinalityJoinWhere = (0, combi_1.seq)("[", cds_integer_1.CDSInteger, ":", joinType, "WHERE", cds_condition_1.CDSCondition, "]");
23
+ const pathFilter = (0, combi_1.altPrio)(cardinalityJoinWhere, cardinalityJoin, joinRedirect, (0, combi_1.seq)("[", cds_integer_1.CDSInteger, ":", cds_condition_1.CDSCondition, "]"), (0, combi_1.seq)("[", cds_condition_1.CDSCondition, "]"));
24
+ // Each dotted segment may have its own path filter: A[cond].B[cond].C
25
+ // The final segment may also be a string literal: #enum.'value'
26
+ // A segment may have a parameterized call: _Assoc( P_Key : value ) or _Assoc[filter]
27
+ const segment = (0, combi_1.seq)(".", (0, combi_1.altPrio)(cds_string_1.CDSString, cds_name_1.CDSName), (0, combi_1.opt)((0, combi_1.altPrio)(cds_parameters_select_1.CDSParametersSelect, cds_parameters_1.CDSParameters)), (0, combi_1.opt)(pathFilter));
28
+ return (0, combi_1.seq)(cds_name_1.CDSName, (0, combi_1.opt)((0, combi_1.altPrio)(cds_parameters_1.CDSParameters, cds_parameters_select_1.CDSParametersSelect)), (0, combi_1.opt)(pathFilter), (0, combi_1.star)(segment));
11
29
  }
12
30
  }
13
31
  exports.CDSPrefixedName = CDSPrefixedName;
@@ -5,7 +5,10 @@ const _1 = require(".");
5
5
  const combi_1 = require("../../abap/2_statements/combi");
6
6
  class CDSSource extends combi_1.Expression {
7
7
  getRunnable() {
8
- return (0, combi_1.seq)(_1.CDSName, (0, combi_1.optPrio)(_1.CDSParametersSelect), (0, combi_1.opt)((0, combi_1.altPrio)(_1.CDSAs, _1.CDSName)));
8
+ const singleSource = (0, combi_1.seq)(_1.CDSName, (0, combi_1.optPrio)(_1.CDSParametersSelect), (0, combi_1.opt)((0, combi_1.altPrio)(_1.CDSAs, _1.CDSName)));
9
+ // FROM ( src [JOIN src ON cond]* ) — parenthesized join chain as primary source
10
+ const parenSource = (0, combi_1.seq)("(", singleSource, (0, combi_1.star)(_1.CDSJoin), ")");
11
+ return (0, combi_1.altPrio)(parenSource, singleSource);
9
12
  }
10
13
  }
11
14
  exports.CDSSource = CDSSource;
@@ -4,10 +4,12 @@ exports.CDSString = void 0;
4
4
  const combi_1 = require("../../abap/2_statements/combi");
5
5
  class CDSString extends combi_1.Expression {
6
6
  getRunnable() {
7
- const abap = (0, combi_1.seq)("abap", ".", (0, combi_1.regex)(/^char'\w'$/));
8
- // https://stackoverflow.com/a/57754227
9
- const reg = (0, combi_1.regex)(/^'([A-Za-zÀ-ž\u0370-\u03FF\u0400-\u04FF:\| -_]|'')*'$/);
10
- return (0, combi_1.altPrio)(reg, abap);
7
+ // Allow any character except unescaped single quote; '' is an escaped single quote
8
+ const reg = (0, combi_1.regex)(/^'([^']|'')*'$/);
9
+ // Typed literal: abap.char 'X' — previously lexed as abap . char'X' (single token)
10
+ // now correctly lexed as three tokens: abap, ., char, 'value'
11
+ const abap = (0, combi_1.seq)("abap", ".", (0, combi_1.regex)(/^char$/), reg);
12
+ return (0, combi_1.altPrio)(abap, reg);
11
13
  }
12
14
  }
13
15
  exports.CDSString = CDSString;
@@ -20,6 +20,7 @@ __exportStar(require("./cds_annotation_array"), exports);
20
20
  __exportStar(require("./cds_annotation_object"), exports);
21
21
  __exportStar(require("./cds_annotation_simple"), exports);
22
22
  __exportStar(require("./cds_annotation"), exports);
23
+ __exportStar(require("./cds_arith_paren"), exports);
23
24
  __exportStar(require("./cds_arithmetics"), exports);
24
25
  __exportStar(require("./cds_as"), exports);
25
26
  __exportStar(require("./cds_association"), exports);
@@ -30,6 +31,7 @@ __exportStar(require("./cds_composition"), exports);
30
31
  __exportStar(require("./cds_condition"), exports);
31
32
  __exportStar(require("./cds_define_abstract"), exports);
32
33
  __exportStar(require("./cds_define_custom"), exports);
34
+ __exportStar(require("./cds_define_hierarchy"), exports);
33
35
  __exportStar(require("./cds_define_projection"), exports);
34
36
  __exportStar(require("./cds_define_table_function"), exports);
35
37
  __exportStar(require("./cds_define_view"), exports);
@@ -74,7 +74,7 @@ class Registry {
74
74
  }
75
75
  static abaplintVersion() {
76
76
  // magic, see build script "version.sh"
77
- return "2.115.25";
77
+ return "2.115.27";
78
78
  }
79
79
  getDDICReferences() {
80
80
  return this.ddicReferences;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.115.25",
3
+ "version": "2.115.27",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "homepage": "https://abaplint.org",
52
52
  "devDependencies": {
53
- "@microsoft/api-extractor": "^7.56.3",
53
+ "@microsoft/api-extractor": "^7.57.5",
54
54
  "@types/chai": "^4.3.20",
55
55
  "@types/mocha": "^10.0.10",
56
56
  "@types/node": "^24.10.13",
@@ -63,7 +63,7 @@
63
63
  "typescript": "^5.9.3"
64
64
  },
65
65
  "dependencies": {
66
- "fast-xml-parser": "^5.3.5",
66
+ "fast-xml-parser": "^5.3.9",
67
67
  "json5": "^2.2.3",
68
68
  "vscode-languageserver-types": "^3.17.5"
69
69
  }