@sap/cds-compiler 2.11.4 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -1
- package/bin/cds_update_identifiers.js +7 -7
- package/bin/cdsc.js +9 -10
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +12 -0
- package/lib/api/main.js +2 -0
- package/lib/api/options.js +2 -2
- package/lib/base/message-registry.js +31 -2
- package/lib/base/model.js +1 -0
- package/lib/base/optionProcessorHelper.js +97 -69
- package/lib/checks/.eslintrc.json +2 -0
- package/lib/checks/actionsFunctions.js +2 -1
- package/lib/checks/foreignKeys.js +4 -4
- package/lib/checks/managedInType.js +4 -4
- package/lib/checks/queryNoDbArtifacts.js +1 -3
- package/lib/checks/sql-snippets.js +93 -0
- package/lib/checks/validator.js +8 -0
- package/lib/compiler/assert-consistency.js +5 -3
- package/lib/compiler/base.js +0 -1
- package/lib/compiler/checks.js +32 -9
- package/lib/compiler/definer.js +25 -4
- package/lib/compiler/index.js +1 -1
- package/lib/compiler/propagator.js +3 -2
- package/lib/compiler/resolver.js +97 -6
- package/lib/compiler/shared.js +12 -1
- package/lib/compiler/utils.js +7 -0
- package/lib/edm/annotations/genericTranslation.js +34 -17
- package/lib/edm/annotations/preprocessAnnotations.js +1 -1
- package/lib/edm/csn2edm.js +1 -1
- package/lib/edm/edm.js +8 -8
- package/lib/edm/edmPreprocessor.js +30 -23
- package/lib/edm/edmUtils.js +11 -12
- package/lib/gen/Dictionary.json +82 -40
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/language.tokens +15 -14
- package/lib/gen/languageLexer.interp +9 -1
- package/lib/gen/languageLexer.js +830 -779
- package/lib/gen/languageLexer.tokens +7 -6
- package/lib/gen/languageParser.js +2401 -2282
- package/lib/json/from-csn.js +47 -16
- package/lib/json/to-csn.js +17 -5
- package/lib/language/antlrParser.js +3 -3
- package/lib/language/docCommentParser.js +1 -1
- package/lib/language/genericAntlrParser.js +68 -51
- package/lib/language/language.g4 +128 -74
- package/lib/language/multiLineStringParser.js +536 -0
- package/lib/main.d.ts +5 -3
- package/lib/main.js +3 -2
- package/lib/model/csnRefs.js +116 -68
- package/lib/model/csnUtils.js +40 -48
- package/lib/model/enrichCsn.js +30 -14
- package/lib/optionProcessor.js +3 -3
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +1 -1
- package/lib/render/toCdl.js +193 -79
- package/lib/render/toHdbcds.js +179 -95
- package/lib/render/toRename.js +7 -10
- package/lib/render/toSql.js +57 -40
- package/lib/render/utils/common.js +24 -5
- package/lib/render/utils/sql.js +6 -4
- package/lib/transform/braceExpression.js +4 -2
- package/lib/transform/db/associations.js +389 -0
- package/lib/transform/db/cdsPersistence.js +150 -0
- package/lib/transform/db/constraints.js +6 -4
- package/lib/transform/db/draft.js +3 -2
- package/lib/transform/db/expansion.js +4 -5
- package/lib/transform/db/flattening.js +5 -6
- package/lib/transform/db/temporal.js +236 -0
- package/lib/transform/db/transformExists.js +36 -23
- package/lib/transform/forHanaNew.js +35 -626
- package/lib/transform/forOdataNew.js +5 -4
- package/lib/transform/localized.js +3 -14
- package/lib/transform/odata/generateForeignKeyElements.js +2 -2
- package/lib/transform/transformUtilsNew.js +13 -13
- package/lib/transform/translateAssocsToJoins.js +8 -8
- package/lib/transform/universalCsnEnricher.js +217 -47
- package/lib/utils/file.js +2 -1
- package/lib/utils/timetrace.js +8 -2
- package/package.json +1 -1
package/lib/language/language.g4
CHANGED
|
@@ -490,7 +490,7 @@ projectionSpec returns[ query ] locals[ src ]
|
|
|
490
490
|
// now a simplified `tableTerm`:
|
|
491
491
|
{
|
|
492
492
|
$src = { path: [], scope: 0 };
|
|
493
|
-
$query = { op: this.
|
|
493
|
+
$query = { op: this.valueWithTokenLocation( 'SELECT', $proj ), from: $src, location: this.startLocation() };
|
|
494
494
|
}
|
|
495
495
|
fromPath[ $src, 'artref']
|
|
496
496
|
( ':'
|
|
@@ -983,6 +983,7 @@ mixinElementDef[ outer ] locals[ art ]
|
|
|
983
983
|
|
|
984
984
|
misplacedAnnotations[ annos, messageId ]
|
|
985
985
|
:
|
|
986
|
+
// No docComment() here
|
|
986
987
|
annotationAssignment_ll1[ $annos ]+
|
|
987
988
|
{ if ($messageId) // issue specified in central registry
|
|
988
989
|
this.message( messageId, this.tokenLocation( $ctx.start, this.getCurrentToken() ) );
|
|
@@ -1078,7 +1079,7 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
|
|
|
1078
1079
|
annotationAssignment_ll1[ $annos ]*
|
|
1079
1080
|
requiredSemi // also req after foreign key spec
|
|
1080
1081
|
|
|
|
1081
|
-
l=LOCALIZED { $art.localized = this.
|
|
1082
|
+
l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
|
|
1082
1083
|
typeRefOptArgs[ $art ]
|
|
1083
1084
|
{ this.docComment( $annos ); }
|
|
1084
1085
|
annotationAssignment_ll1[ $annos ]*
|
|
@@ -1146,7 +1147,7 @@ selectItemDef[ outer ] locals[ annos = [] ]
|
|
|
1146
1147
|
@after{ if ($ctx.art) this.attachLocation($art.art); }
|
|
1147
1148
|
:
|
|
1148
1149
|
star='*'
|
|
1149
|
-
{ $outer.push( this.
|
|
1150
|
+
{ $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
|
|
1150
1151
|
|
|
|
1151
1152
|
{ this.docComment( $annos ); }
|
|
1152
1153
|
annotationAssignment_atn[ $annos ]*
|
|
@@ -1156,8 +1157,8 @@ selectItemDef[ outer ] locals[ annos = [] ]
|
|
|
1156
1157
|
key=KEY?
|
|
1157
1158
|
art=selectItemDefBody[ $outer, $annos ]
|
|
1158
1159
|
{
|
|
1159
|
-
if ($virtual) $art.art.virtual = this.
|
|
1160
|
-
if ($key) $art.art.key = this.
|
|
1160
|
+
if ($virtual) $art.art.virtual = this.valueWithTokenLocation( true, $virtual );
|
|
1161
|
+
if ($key) $art.art.key = this.valueWithTokenLocation( true, $key );
|
|
1161
1162
|
}
|
|
1162
1163
|
;
|
|
1163
1164
|
|
|
@@ -1190,7 +1191,7 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
|
|
|
1190
1191
|
excludingClause[ $art ]?
|
|
1191
1192
|
|
|
|
1192
1193
|
star='*'
|
|
1193
|
-
{ $art.inline = [ this.
|
|
1194
|
+
{ $art.inline = [ this.valueWithTokenLocation( '*', $star ) ]; }
|
|
1194
1195
|
)
|
|
1195
1196
|
)?
|
|
1196
1197
|
|
|
|
@@ -1239,7 +1240,7 @@ selectItemInlineDef[ outer ] locals[ annos = [] ]
|
|
|
1239
1240
|
@after{ if ($ctx.art) this.attachLocation($art.art); }
|
|
1240
1241
|
:
|
|
1241
1242
|
star='*'
|
|
1242
|
-
{ $outer.push( this.
|
|
1243
|
+
{ $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
|
|
1243
1244
|
|
|
|
1244
1245
|
{ this.docComment( $annos ); }
|
|
1245
1246
|
annotationAssignment_atn[ $annos ]*
|
|
@@ -1300,15 +1301,17 @@ entityParameterDef[ outer ] locals[ art, annos = [] ]
|
|
|
1300
1301
|
annotationAssignment_fix[ $annos ]*
|
|
1301
1302
|
typeSpec[ $art ]
|
|
1302
1303
|
( DEFAULT expr=expression { $art.default = $expr.expr; } )?
|
|
1304
|
+
{ this.docComment( $annos ); }
|
|
1305
|
+
annotationAssignment_ll1[ $annos ]*
|
|
1303
1306
|
;
|
|
1304
1307
|
|
|
1305
1308
|
nullability[ art ]
|
|
1306
1309
|
:
|
|
1307
1310
|
not=NOT n1=NULL
|
|
1308
|
-
{ $art.notNull = this.
|
|
1311
|
+
{ $art.notNull = this.valueWithTokenLocation( true, $not, $n1 ); }
|
|
1309
1312
|
|
|
|
1310
1313
|
n2=NULL
|
|
1311
|
-
{ $art.notNull = this.
|
|
1314
|
+
{ $art.notNull = this.valueWithTokenLocation( false, $n2 ); }
|
|
1312
1315
|
;
|
|
1313
1316
|
|
|
1314
1317
|
elementProperties[ elem ]
|
|
@@ -1465,7 +1468,7 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
|
|
|
1465
1468
|
{ this.docComment( $annos ); }
|
|
1466
1469
|
annotationAssignment_ll1[ $annos ]* requiredSemi
|
|
1467
1470
|
|
|
|
1468
|
-
l=LOCALIZED { $art.localized = this.
|
|
1471
|
+
l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
|
|
1469
1472
|
typeRefOptArgs[ $art ]
|
|
1470
1473
|
{ this.docComment( $annos ); }
|
|
1471
1474
|
annotationAssignment_ll1[ $annos ]*
|
|
@@ -1769,21 +1772,21 @@ orderByClause[ inQuery ] returns [ query ]
|
|
|
1769
1772
|
|
|
1770
1773
|
overOrderByClause returns [ expr ]
|
|
1771
1774
|
:
|
|
1772
|
-
o=ORDER b=BY { $expr = { op: this.
|
|
1775
|
+
o=ORDER b=BY { $expr = { op: this.valueWithTokenLocation( 'orderBy', $o, $b ) , args: [] }}
|
|
1773
1776
|
ob1=orderBySpec { $expr.args.push( $ob1.ob ); }
|
|
1774
1777
|
( ',' obn=orderBySpec { $expr.args.push( $obn.ob ); } )*
|
|
1775
1778
|
;
|
|
1776
1779
|
|
|
1777
1780
|
partitionByClause returns [ expr ]
|
|
1778
1781
|
:
|
|
1779
|
-
p=PARTITION b=BY { $expr = { op: this.
|
|
1782
|
+
p=PARTITION b=BY { $expr = { op: this.valueWithTokenLocation( 'partitionBy', $p, $b ) , args: [] }}
|
|
1780
1783
|
e1=expression { $expr.args.push( $e1.expr ); }
|
|
1781
1784
|
( ',' en=expression { $expr.args.push( $en.expr ); } )*
|
|
1782
1785
|
;
|
|
1783
1786
|
|
|
1784
1787
|
windowFrameClause returns [ wf ]
|
|
1785
1788
|
:
|
|
1786
|
-
r=ROWS { $wf = { op: this.
|
|
1789
|
+
r=ROWS { $wf = { op: this.valueWithTokenLocation( 'rows', $r ) , args: [] }}
|
|
1787
1790
|
wfe=windowFrameExtentSpec { $wf.args.push( $wfe.wfe ); }
|
|
1788
1791
|
;
|
|
1789
1792
|
|
|
@@ -1793,7 +1796,7 @@ windowFrameExtentSpec returns[ wfe ]
|
|
|
1793
1796
|
windowFrameStartSpec [ $wfe ]
|
|
1794
1797
|
|
|
|
1795
1798
|
b=BETWEEN
|
|
1796
|
-
{ $wfe = { op: this.
|
|
1799
|
+
{ $wfe = { op: this.valueWithTokenLocation( 'frameBetween', $b ), args: [] } }
|
|
1797
1800
|
wfb1=windowFrameBoundSpec { $wfe.args.push( $wfb1.wfb ); }
|
|
1798
1801
|
AND
|
|
1799
1802
|
wfb2=windowFrameBoundSpec { $wfe.args.push( $wfb2.wfb ); }
|
|
@@ -1805,12 +1808,12 @@ windowFrameBoundSpec returns [ wfb ]
|
|
|
1805
1808
|
// #ATN: Not ll1 because `UNBOUNDED` could also be part of the windowFrameStartSpec
|
|
1806
1809
|
// `UNBOUNDED` would then be immediately followed by `PRECEDING`
|
|
1807
1810
|
u=UNBOUNDED f=FOLLOWING
|
|
1808
|
-
{ $wfb = { op: this.
|
|
1811
|
+
{ $wfb = { op: this.valueWithTokenLocation( 'unboundedFollowing', $u, $f ), args: []} }
|
|
1809
1812
|
|
|
|
1810
1813
|
// #ATN: Not ll1 because `Number` could also be part of the windowFrameStartSpec
|
|
1811
1814
|
// `Number` would then be immediately followed by `PRECEDING`
|
|
1812
1815
|
n=Number f=FOLLOWING
|
|
1813
|
-
{ $wfb = { op: this.
|
|
1816
|
+
{ $wfb = { op: this.valueWithTokenLocation( 'following', $n, $f ), args: [ this.numberLiteral( $n ) ]} }
|
|
1814
1817
|
|
|
|
1815
1818
|
{ $wfb = {} }
|
|
1816
1819
|
windowFrameStartSpec [ $wfb ]
|
|
@@ -1820,19 +1823,19 @@ windowFrameStartSpec [ wf ]
|
|
|
1820
1823
|
:
|
|
1821
1824
|
u=UNBOUNDED p=PRECEDING
|
|
1822
1825
|
{
|
|
1823
|
-
$wf.op = this.
|
|
1826
|
+
$wf.op = this.valueWithTokenLocation( 'unboundedPreceding', $u, $p );
|
|
1824
1827
|
$wf.args = [];
|
|
1825
1828
|
}
|
|
1826
1829
|
|
|
|
1827
1830
|
n=Number p=PRECEDING
|
|
1828
1831
|
{
|
|
1829
|
-
$wf.op = this.
|
|
1832
|
+
$wf.op = this.valueWithTokenLocation( 'preceding', $p );
|
|
1830
1833
|
$wf.args = [ this.numberLiteral( $n ) ];
|
|
1831
1834
|
}
|
|
1832
1835
|
|
|
|
1833
1836
|
c=CURRENT r=ROW
|
|
1834
1837
|
{
|
|
1835
|
-
$wf.op = this.
|
|
1838
|
+
$wf.op = this.valueWithTokenLocation( 'currentRow', $c, $r );
|
|
1836
1839
|
$wf.args = [];
|
|
1837
1840
|
}
|
|
1838
1841
|
;
|
|
@@ -1840,7 +1843,7 @@ windowFrameStartSpec [ wf ]
|
|
|
1840
1843
|
overClause returns [ over ]
|
|
1841
1844
|
@after { this.attachLocation($over); }
|
|
1842
1845
|
:
|
|
1843
|
-
o=OVER { $over = { op: this.
|
|
1846
|
+
o=OVER { $over = { op: this.valueWithTokenLocation( 'over', $o ) , args: [] } }
|
|
1844
1847
|
'('
|
|
1845
1848
|
( pb=partitionByClause { $over.args.push( $pb.expr ); } )?
|
|
1846
1849
|
( ob=overOrderByClause { $over.args.push( $ob.expr ); } )?
|
|
@@ -1861,11 +1864,11 @@ limitClause[ inQuery ] returns [ query ]
|
|
|
1861
1864
|
orderBySpec returns[ ob ]
|
|
1862
1865
|
:
|
|
1863
1866
|
e=expression { $ob = $e.expr; }
|
|
1864
|
-
( asc=ASC { $ob.sort = this.
|
|
1865
|
-
| desc=DESC { $ob.sort = this.
|
|
1867
|
+
( asc=ASC { $ob.sort = this.valueWithTokenLocation( 'asc', $asc ); }
|
|
1868
|
+
| desc=DESC { $ob.sort = this.valueWithTokenLocation( 'desc', $desc ); }
|
|
1866
1869
|
)?
|
|
1867
1870
|
( nb=NULLS ne=( FIRST | LAST )
|
|
1868
|
-
{ $ob.nulls = this.
|
|
1871
|
+
{ $ob.nulls = this.valueWithTokenLocation( $ne.text.toLowerCase(), $nb, $ne ); }
|
|
1869
1872
|
)?
|
|
1870
1873
|
;
|
|
1871
1874
|
|
|
@@ -1888,7 +1891,7 @@ queryPrimary returns[ query = {} ]
|
|
|
1888
1891
|
{ $query = this.surroundByParens( $qe.query, $open, $close ); }
|
|
1889
1892
|
|
|
|
1890
1893
|
select=SELECT
|
|
1891
|
-
{ $query = { op: this.
|
|
1894
|
+
{ $query = { op: this.valueWithTokenLocation( 'SELECT', $select ), location: this.startLocation() }; }
|
|
1892
1895
|
(
|
|
1893
1896
|
FROM querySource[ $query ]
|
|
1894
1897
|
(
|
|
@@ -1897,13 +1900,13 @@ queryPrimary returns[ query = {} ]
|
|
|
1897
1900
|
'}' INTO
|
|
1898
1901
|
)?
|
|
1899
1902
|
( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
|
|
1900
|
-
{ $query.quantifier = this.
|
|
1903
|
+
{ $query.quantifier = this.valueWithTokenLocation( $ad.text.toLowerCase(), $ad ); }
|
|
1901
1904
|
)?
|
|
1902
1905
|
bracedSelectItemListDef[ $query ]?
|
|
1903
1906
|
excludingClause[ $query ]?
|
|
1904
1907
|
|
|
|
1905
1908
|
( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
|
|
1906
|
-
{ $query.quantifier = this.
|
|
1909
|
+
{ $query.quantifier = this.valueWithTokenLocation( $ad.text.toLowerCase(), $ad ); }
|
|
1907
1910
|
)?
|
|
1908
1911
|
{ $query.columns = []; } // set it early to avoid "wildcard" errors
|
|
1909
1912
|
selectItemDef[ $query.columns ]
|
|
@@ -1957,8 +1960,8 @@ joinOp[ left ] returns[ table ] locals [ join ]
|
|
|
1957
1960
|
| t1=RIGHT t2=OUTER? c=joinCardinality? op=JOIN { $join = 'right' }
|
|
1958
1961
|
| t1=FULL t2=OUTER? c=joinCardinality? op=JOIN { $join = 'full' }
|
|
1959
1962
|
)
|
|
1960
|
-
{ $table = { op: this.
|
|
1961
|
-
join: this.
|
|
1963
|
+
{ $table = { op: this.valueWithTokenLocation( 'join', $op ),
|
|
1964
|
+
join: this.valueWithTokenLocation( $join, $t1 || $op, $t2 ),
|
|
1962
1965
|
args: ($left ? [$left] : []),
|
|
1963
1966
|
location: $left && $left.location };
|
|
1964
1967
|
if ($ctx.c) $table.cardinality = $c.joinCard; }
|
|
@@ -2065,24 +2068,24 @@ fromPath[ qp, idkind ]
|
|
|
2065
2068
|
|
|
2066
2069
|
condition returns [ cond ] locals [ args = [], orl = [] ]
|
|
2067
2070
|
@after{
|
|
2068
|
-
$cond = ($args.length
|
|
2071
|
+
$cond = ($args.length === 1)
|
|
2069
2072
|
? this.attachLocation( $args[0] )
|
|
2070
2073
|
: this.attachLocation({ op: $orl[0], args: $args });
|
|
2071
2074
|
}
|
|
2072
2075
|
:
|
|
2073
2076
|
c1=conditionAnd { $args.push($c1.cond); }
|
|
2074
|
-
( or=OR c2=conditionAnd { $args.push($c2.cond); $orl.push(this.
|
|
2077
|
+
( or=OR c2=conditionAnd { $args.push($c2.cond); $orl.push(this.valueWithTokenLocation( 'or', $or ))} )*
|
|
2075
2078
|
;
|
|
2076
2079
|
|
|
2077
2080
|
conditionAnd returns [ cond ] locals [ args = [], andl = [] ]
|
|
2078
2081
|
@after{
|
|
2079
|
-
$cond = ($args.length
|
|
2082
|
+
$cond = ($args.length === 1)
|
|
2080
2083
|
? $args[0]
|
|
2081
2084
|
: this.attachLocation({ op: $andl[0], args: $args });
|
|
2082
2085
|
}
|
|
2083
2086
|
:
|
|
2084
2087
|
c1=conditionTerm { $args.push($c1.cond); }
|
|
2085
|
-
( and=AND c2=conditionTerm { $args.push($c2.cond); $andl.push(this.
|
|
2088
|
+
( and=AND c2=conditionTerm { $args.push($c2.cond); $andl.push(this.valueWithTokenLocation( 'and', $and )) } )*
|
|
2086
2089
|
;
|
|
2087
2090
|
|
|
2088
2091
|
conditionTerm returns [ cond ]
|
|
@@ -2091,38 +2094,38 @@ conditionTerm returns [ cond ]
|
|
|
2091
2094
|
}
|
|
2092
2095
|
:
|
|
2093
2096
|
nt=NOT ct=conditionTerm
|
|
2094
|
-
{ $cond = { op: this.
|
|
2097
|
+
{ $cond = { op: this.valueWithTokenLocation( 'not', $nt ), args: [ $ct.cond ] }; }
|
|
2095
2098
|
|
|
|
2096
2099
|
ex=EXISTS
|
|
2097
2100
|
(
|
|
2098
2101
|
open='(' qe=queryExpression close=')'
|
|
2099
|
-
{ $cond = { op: this.
|
|
2102
|
+
{ $cond = { op: this.valueWithTokenLocation( 'exists', $ex ),
|
|
2100
2103
|
args: [ this.surroundByParens( $qe.query, $open, $close, true ) ] }; }
|
|
2101
2104
|
|
|
|
2102
2105
|
qm=( HideAlternatives | '?' )
|
|
2103
|
-
{ $cond = { op: this.
|
|
2104
|
-
{ param: this.
|
|
2106
|
+
{ $cond = { op: this.valueWithTokenLocation( 'exists', $ex ), args: [
|
|
2107
|
+
{ param: this.valueWithTokenLocation( '?', $qm ), scope: 'param' }
|
|
2105
2108
|
] };
|
|
2106
2109
|
this.csnParseOnly( 'Dynamic parameter "?" is not supported', $qm );
|
|
2107
2110
|
}
|
|
2108
2111
|
|
|
|
2109
2112
|
ep=valuePath[ 'ref' ]
|
|
2110
2113
|
{ $ep.qp['$'+'expected'] = 'exists';
|
|
2111
|
-
$cond = { op: this.
|
|
2114
|
+
$cond = { op: this.valueWithTokenLocation( 'exists', $ex ), args: [ $ep.qp ] };
|
|
2112
2115
|
}
|
|
2113
2116
|
)
|
|
2114
2117
|
|
|
|
2115
2118
|
expr=expression // see @after
|
|
2116
2119
|
(
|
|
2117
2120
|
rel=( '=' | '<>' | '>' | '>=' | '<' | '<=' | '!=' )
|
|
2118
|
-
{ $cond = { op: this.
|
|
2121
|
+
{ $cond = { op: this.valueWithTokenLocation( $rel.text, $rel ), args: [ $expr.expr ] }; }
|
|
2119
2122
|
( asa=( ANY | SOME | ALL )
|
|
2120
|
-
{ $cond.quantifier = this.
|
|
2123
|
+
{ $cond.quantifier = this.valueWithTokenLocation( $asa.text.toLowerCase(), $asa ); }
|
|
2121
2124
|
)?
|
|
2122
2125
|
e2=expression { $cond.args.push($e2.expr); }
|
|
2123
2126
|
|
|
|
2124
2127
|
IS ( inn=NOT NULL | innu=NULL )
|
|
2125
|
-
{ $cond = { op: $inn ? this.
|
|
2128
|
+
{ $cond = { op: $inn ? this.valueWithTokenLocation( 'isNotNull', $inn ) : this.valueWithTokenLocation( 'isNull', $innu ), args: [ $expr.expr ] }; }
|
|
2126
2129
|
|
|
|
2127
2130
|
{ $cond = { args: [ $expr.expr ] }; }
|
|
2128
2131
|
NOT predicate[ $cond, true ]
|
|
@@ -2138,14 +2141,14 @@ predicate[ cond, negated ]
|
|
|
2138
2141
|
// NOT (a BETWEEN b AND c)
|
|
2139
2142
|
:
|
|
2140
2143
|
ino=IN e1=expression // including ExpressionList
|
|
2141
|
-
{ $cond.op = this.
|
|
2144
|
+
{ $cond.op = this.valueWithTokenLocation( (negated) ? 'notIn' : 'in', $ino ); $cond.args.push( $e1.expr ); }
|
|
2142
2145
|
|
|
|
2143
2146
|
bw=BETWEEN e2=expression
|
|
2144
|
-
{ $cond.op = this.
|
|
2147
|
+
{ $cond.op = this.valueWithTokenLocation( (negated) ? 'notBetween' : 'between', $bw ); $cond.args.push( $e2.expr ); }
|
|
2145
2148
|
AND e3=expression { $cond.args.push( $e3.expr ); }
|
|
2146
2149
|
|
|
|
2147
2150
|
lk=LIKE e4=expression
|
|
2148
|
-
{ $cond.op = this.
|
|
2151
|
+
{ $cond.op = this.valueWithTokenLocation( (negated) ? 'notLike' : 'like', $lk ); $cond.args.push( $e4.expr ); }
|
|
2149
2152
|
( ESCAPE e5=expression { $cond.args.push( $e5.expr ); } )?
|
|
2150
2153
|
;
|
|
2151
2154
|
|
|
@@ -2157,7 +2160,7 @@ expression returns [ expr ]
|
|
|
2157
2160
|
or='||' e2=expressionSum
|
|
2158
2161
|
{
|
|
2159
2162
|
$expr = {
|
|
2160
|
-
op: this.
|
|
2163
|
+
op: this.valueWithTokenLocation( '||', $or ), args: [$expr, $e2.expr],
|
|
2161
2164
|
location: this.combinedLocation( $expr, $e2.expr ) };
|
|
2162
2165
|
}
|
|
2163
2166
|
)*
|
|
@@ -2171,7 +2174,7 @@ expressionSum returns [ expr ]
|
|
|
2171
2174
|
op=( '+' | '-' ) e2=expressionFactor
|
|
2172
2175
|
{
|
|
2173
2176
|
$expr = {
|
|
2174
|
-
op: this.
|
|
2177
|
+
op: this.valueWithTokenLocation( $op.text, $op ), args: [$expr, $e2.expr],
|
|
2175
2178
|
location: this.combinedLocation( $expr, $e2.expr ) };
|
|
2176
2179
|
}
|
|
2177
2180
|
)*
|
|
@@ -2185,7 +2188,7 @@ expressionFactor returns [ expr ]
|
|
|
2185
2188
|
op=( '*' | '/' ) e2=expressionTerm
|
|
2186
2189
|
{
|
|
2187
2190
|
$expr = {
|
|
2188
|
-
op: this.
|
|
2191
|
+
op: this.valueWithTokenLocation( $op.text, $op ), args: [$expr, $e2.expr],
|
|
2189
2192
|
location: this.combinedLocation( $expr, $e2.expr ) };
|
|
2190
2193
|
}
|
|
2191
2194
|
)*
|
|
@@ -2205,7 +2208,7 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
|
|
|
2205
2208
|
{ $expr = $sf.ret; }
|
|
2206
2209
|
|
|
|
2207
2210
|
ca=CASE
|
|
2208
|
-
{ $expr = { op : this.
|
|
2211
|
+
{ $expr = { op : this.valueWithTokenLocation( 'case', $ca ), args: [] }; }
|
|
2209
2212
|
(
|
|
2210
2213
|
e2=expression { $expr.args.push($e2.expr); }
|
|
2211
2214
|
( ow=WHEN ew=expression THEN e3=expression
|
|
@@ -2223,7 +2226,7 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
|
|
|
2223
2226
|
|
|
|
2224
2227
|
ne=NEW nqp=valuePath[ 'ref', null] // token rewrite for NEW
|
|
2225
2228
|
// please note: there will be no compiler-supported code completion after NEW
|
|
2226
|
-
{ $expr = { op: this.
|
|
2229
|
+
{ $expr = { op: this.valueWithTokenLocation( 'new', $ne ), args: [] };
|
|
2227
2230
|
this.notSupportedYet( $ne ); }
|
|
2228
2231
|
|
|
|
2229
2232
|
vp=valuePath[ 'ref', null ] { $expr = this.valuePathAst( $vp.qp ); }
|
|
@@ -2242,7 +2245,7 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
|
|
|
2242
2245
|
)
|
|
2243
2246
|
|
|
|
2244
2247
|
qm=( HideAlternatives | '?' )
|
|
2245
|
-
{ $expr = { param: this.
|
|
2248
|
+
{ $expr = { param: this.valueWithTokenLocation( '?', $qm ), scope: 'param' };
|
|
2246
2249
|
this.csnParseOnly( 'Dynamic parameter "?" is not supported', $qm );
|
|
2247
2250
|
}
|
|
2248
2251
|
|
|
|
@@ -2260,7 +2263,7 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
|
|
|
2260
2263
|
close=')'
|
|
2261
2264
|
{
|
|
2262
2265
|
if ($expr.length > 1)
|
|
2263
|
-
$expr = { op: this.
|
|
2266
|
+
$expr = { op: this.valueWithTokenLocation( ',', $open ), args: $expr };
|
|
2264
2267
|
else if ($expr[0]) // can be `null` if condition failed to parse
|
|
2265
2268
|
$expr = this.surroundByParens( $expr[0], $open, $close );
|
|
2266
2269
|
}
|
|
@@ -2300,7 +2303,7 @@ specialFunction returns [ ret = { } ] locals[ art = {} ]
|
|
|
2300
2303
|
ca=CAST open='('
|
|
2301
2304
|
{
|
|
2302
2305
|
$ret = {
|
|
2303
|
-
op: this.
|
|
2306
|
+
op: this.valueWithTokenLocation( 'cast', $ca ),
|
|
2304
2307
|
args: [ ],
|
|
2305
2308
|
location: this.tokenLocation( $ca )
|
|
2306
2309
|
};
|
|
@@ -2370,15 +2373,15 @@ pathArguments[ pathStep, considerSpecial ]
|
|
|
2370
2373
|
funcExpression[ $pathStep, $considerSpecial ]
|
|
2371
2374
|
)*
|
|
2372
2375
|
|
|
|
2373
|
-
a=ALL { $pathStep.quantifier = this.
|
|
2376
|
+
a=ALL { $pathStep.quantifier = this.valueWithTokenLocation( 'all', $a ); }
|
|
2374
2377
|
e1=expression { $pathStep.args = [ $e1.expr ]; }
|
|
2375
2378
|
|
|
|
2376
|
-
d=DISTINCT { $pathStep.quantifier = this.
|
|
2379
|
+
d=DISTINCT { $pathStep.quantifier = this.valueWithTokenLocation( 'distinct', $d ); }
|
|
2377
2380
|
e1=expression { $pathStep.args = [ $e1.expr ]; }
|
|
2378
2381
|
( ',' e2=expression { $pathStep.args.push( $e2.expr ); } )*
|
|
2379
2382
|
|
|
|
2380
2383
|
star='*'
|
|
2381
|
-
{ $pathStep.args = [ { location: this.tokenLocation($star), val: '*', literal: 'token' } ]; }
|
|
2384
|
+
{ $pathStep.args = [ { location: this.tokenLocation( $star ), val: '*', literal: 'token' } ]; }
|
|
2382
2385
|
|
|
|
2383
2386
|
{ $pathStep.args = []; }
|
|
2384
2387
|
)
|
|
@@ -2452,7 +2455,7 @@ optionalWhereForFilter
|
|
|
2452
2455
|
|
|
2453
2456
|
// Simple paths and values ---------------------------------------------------
|
|
2454
2457
|
|
|
2455
|
-
annoValueBase returns[ val ] locals [
|
|
2458
|
+
annoValueBase returns[ val ] locals [ seenEllipsis = false ]
|
|
2456
2459
|
@after { this.attachLocation($val); }
|
|
2457
2460
|
:
|
|
2458
2461
|
{ $val = { literal: 'struct', location: this.startLocation() }; }
|
|
@@ -2472,30 +2475,43 @@ annoValueBase returns[ val ] locals [ hasEllipsis=0 ]
|
|
|
2472
2475
|
'['
|
|
2473
2476
|
(
|
|
2474
2477
|
(
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2478
|
+
head=arrayValue { $val.val.push( $head.val ); }
|
|
2479
|
+
|
|
|
2480
|
+
e='...' ( UP TO upTo=arrayValue )?
|
|
2481
|
+
{{
|
|
2482
|
+
const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
|
|
2483
|
+
$val.val.push( item );
|
|
2484
|
+
if ($ctx.upTo) item.upTo = $upTo.val;
|
|
2485
|
+
$seenEllipsis = !$ctx.upTo || 'upTo';
|
|
2486
|
+
}}
|
|
2482
2487
|
)
|
|
2483
2488
|
(
|
|
2484
2489
|
',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
|
|
2485
2490
|
(
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2491
|
+
tail=arrayValue { $val.val.push( $tail.val ); }
|
|
2492
|
+
|
|
|
2493
|
+
{ $ctx.upTo = null; } // is not reset
|
|
2494
|
+
e='...' ( UP TO upTo=arrayValue )?
|
|
2495
|
+
{{
|
|
2496
|
+
const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
|
|
2497
|
+
if ($ctx.upTo) item.upTo = $upTo.val;
|
|
2498
|
+
$val.val.push( item );
|
|
2499
|
+
if ($seenEllipsis === true) // TODO: adapt msg to UP TO
|
|
2500
|
+
this.error( 'syntax-unexpected-ellipsis', $e, { code: '...' },
|
|
2501
|
+
'Expected no more than one $(CODE)' );
|
|
2502
|
+
else
|
|
2503
|
+
$seenEllipsis = !$ctx.upTo || 'upTo';
|
|
2504
|
+
}}
|
|
2495
2505
|
)
|
|
2496
2506
|
)*
|
|
2497
2507
|
)?
|
|
2498
|
-
']'
|
|
2508
|
+
cb=']'
|
|
2509
|
+
{
|
|
2510
|
+
if ($seenEllipsis === 'upTo')
|
|
2511
|
+
this.error( 'syntax-expecting-ellipsis', $cb, // at closing bracket
|
|
2512
|
+
{ code: '... up to', newcode: '...' },
|
|
2513
|
+
'Expecting an array item $(NEWCODE) after an item with $(CODE)' );
|
|
2514
|
+
}
|
|
2499
2515
|
|
|
|
2500
2516
|
v1=literalValue { $val = $v1.val; }
|
|
2501
2517
|
|
|
|
@@ -2728,6 +2744,7 @@ ident[ category ] returns[ id ]
|
|
|
2728
2744
|
| THEN
|
|
2729
2745
|
| TRAILING
|
|
2730
2746
|
| UNION
|
|
2747
|
+
| UP
|
|
2731
2748
|
| TO
|
|
2732
2749
|
| TYPE
|
|
2733
2750
|
| USING
|
|
@@ -2752,9 +2769,40 @@ LineComment : '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN);
|
|
|
2752
2769
|
|
|
2753
2770
|
// Values --------------------------------------------------------------------
|
|
2754
2771
|
|
|
2755
|
-
|
|
2772
|
+
// for syntactic code-completion: Combine all three string styles
|
|
2773
|
+
// Note: Use rule `string` instead as that also parses escape sequences!
|
|
2774
|
+
String : SingleLineString
|
|
2775
|
+
| MultiLineString
|
|
2776
|
+
| MutlLineStringBlock;
|
|
2777
|
+
|
|
2778
|
+
fragment SingleLineString
|
|
2756
2779
|
:
|
|
2757
|
-
|
|
2780
|
+
// \u0027 = '\''
|
|
2781
|
+
// \u2028 = LS (Line Separator)
|
|
2782
|
+
// \u2029 = PS (Paragraph Separator)
|
|
2783
|
+
( '\'' ~[\u0027\n\r\u2028\u2029]* '\'' )+ //
|
|
2784
|
+
;
|
|
2785
|
+
|
|
2786
|
+
fragment MultiLineString
|
|
2787
|
+
:
|
|
2788
|
+
('`' ( MultiLineStringContentChar | EscapeSequence )* '`' )
|
|
2789
|
+
;
|
|
2790
|
+
|
|
2791
|
+
fragment MutlLineStringBlock
|
|
2792
|
+
:
|
|
2793
|
+
('```' ( MultiLineStringContentChar | EscapeSequence )* '```')
|
|
2794
|
+
;
|
|
2795
|
+
|
|
2796
|
+
fragment EscapeSequence
|
|
2797
|
+
:
|
|
2798
|
+
// we could list each escape sequence explicitly, but we already
|
|
2799
|
+
// decode them in genericAntlrParser.js, so no need to do work twice.
|
|
2800
|
+
'\\' .
|
|
2801
|
+
;
|
|
2802
|
+
|
|
2803
|
+
fragment MultiLineStringContentChar
|
|
2804
|
+
:
|
|
2805
|
+
(~[\u0060\\]) // \u0060 = '`'
|
|
2758
2806
|
;
|
|
2759
2807
|
|
|
2760
2808
|
QuotedLiteral
|
|
@@ -2763,10 +2811,15 @@ QuotedLiteral
|
|
|
2763
2811
|
( '\'' ~[\u0027\n\r\u2028\u2029]* '\'' )+ // \u0027 = '\''
|
|
2764
2812
|
;
|
|
2765
2813
|
|
|
2814
|
+
// This literal improves error messages for unterminated literals.
|
|
2766
2815
|
UnterminatedLiteral
|
|
2767
2816
|
:
|
|
2768
2817
|
( [xX] | [dD][aA][tT][eE] | [tT][iI][mM][eE] ( [sS][tT][aA][mM][pP] )? )?
|
|
2769
2818
|
'\'' ~[\u0027\n\r\u2028\u2029]* // \u0027 = '\''
|
|
2819
|
+
|
|
|
2820
|
+
('`' ( MultiLineStringContentChar | EscapeSequence )* )
|
|
2821
|
+
|
|
|
2822
|
+
('```' ( MultiLineStringContentChar | EscapeSequence )* )
|
|
2770
2823
|
;
|
|
2771
2824
|
|
|
2772
2825
|
UnterminatedDelimitedIdentifier
|
|
@@ -2899,6 +2952,7 @@ TO : [tT][oO] ; // or make reserved? (is in SQL-92)
|
|
|
2899
2952
|
TYPE : [tT][yY][pP][eE] ;
|
|
2900
2953
|
UNION : [uU][nN][iI][oO][nN] ;
|
|
2901
2954
|
UNBOUNDED : [uU][nN][bB][oO][uU][nN][dD][eE][dD] ;
|
|
2955
|
+
UP : [uU][pP] ;
|
|
2902
2956
|
USING : [uU][sS][iI][nN][gG] ;
|
|
2903
2957
|
VARIABLE : [vV][aA][rR][iI][aA][bB][lL][eE] ;
|
|
2904
2958
|
VIEW : [vV][iI][eE][wW] ;
|