@sap/cds-compiler 5.9.4 → 6.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +117 -319
- package/README.md +1 -1
- package/bin/cds_update_identifiers.js +3 -5
- package/bin/cdsc.js +24 -9
- package/bin/cdshi.js +1 -1
- package/bin/cdsse.js +4 -4
- package/doc/CHANGELOG_BETA.md +11 -0
- package/doc/CHANGELOG_DEPRECATED.md +29 -0
- package/lib/api/main.js +8 -5
- package/lib/api/options.js +12 -10
- package/lib/base/builtins.js +1 -0
- package/lib/base/message-registry.js +191 -99
- package/lib/base/messages.js +35 -21
- package/lib/base/model.js +14 -24
- package/lib/checks/actionsFunctions.js +10 -20
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/elements.js +35 -10
- package/lib/checks/enums.js +31 -0
- package/lib/checks/foreignKeys.js +2 -2
- package/lib/checks/hasPersistedElements.js +5 -0
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/managedWithoutKeys.js +5 -4
- package/lib/checks/queryNoDbArtifacts.js +10 -8
- package/lib/checks/types.js +5 -5
- package/lib/checks/validator.js +6 -4
- package/lib/compiler/assert-consistency.js +13 -9
- package/lib/compiler/checks.js +20 -52
- package/lib/compiler/define.js +31 -6
- package/lib/compiler/extend.js +5 -1
- package/lib/compiler/generate.js +14 -17
- package/lib/compiler/populate.js +8 -31
- package/lib/compiler/propagator.js +21 -35
- package/lib/compiler/resolve.js +64 -29
- package/lib/compiler/shared.js +16 -4
- package/lib/compiler/tweak-assocs.js +1 -1
- package/lib/compiler/utils.js +1 -1
- package/lib/edm/annotations/edmJson.js +23 -20
- package/lib/edm/annotations/genericTranslation.js +12 -10
- package/lib/edm/csn2edm.js +50 -56
- package/lib/edm/edm.js +33 -28
- package/lib/edm/edmInboundChecks.js +2 -2
- package/lib/edm/edmPreprocessor.js +54 -88
- package/lib/edm/edmUtils.js +9 -12
- package/lib/gen/BaseParser.js +63 -52
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +1153 -1165
- package/lib/gen/Dictionary.json +21 -1
- package/lib/json/from-csn.js +70 -43
- package/lib/json/to-csn.js +6 -8
- package/lib/language/multiLineStringParser.js +3 -2
- package/lib/main.d.ts +58 -24
- package/lib/model/cloneCsn.js +3 -0
- package/lib/model/csnUtils.js +28 -39
- package/lib/model/xprAsTree.js +23 -9
- package/lib/modelCompare/compare.js +5 -4
- package/lib/optionProcessor.js +24 -17
- package/lib/parsers/AstBuildingParser.js +81 -25
- package/lib/parsers/XprTree.js +57 -3
- package/lib/parsers/identifiers.js +1 -1
- package/lib/parsers/index.js +0 -3
- package/lib/render/manageConstraints.js +25 -25
- package/lib/render/toCdl.js +173 -170
- package/lib/render/toHdbcds.js +126 -128
- package/lib/render/toRename.js +7 -7
- package/lib/render/toSql.js +128 -125
- package/lib/render/utils/common.js +47 -22
- package/lib/render/utils/delta.js +25 -25
- package/lib/render/utils/operators.js +2 -2
- package/lib/render/utils/pretty.js +5 -5
- package/lib/render/utils/sql.js +13 -13
- package/lib/render/utils/standardDatabaseFunctions.js +115 -103
- package/lib/render/utils/unique.js +4 -4
- package/lib/transform/db/applyTransformations.js +1 -1
- package/lib/transform/db/assertUnique.js +2 -2
- package/lib/transform/db/associations.js +6 -7
- package/lib/transform/db/assocsToQueries/utils.js +4 -5
- package/lib/transform/db/backlinks.js +12 -9
- package/lib/transform/db/cdsPersistence.js +8 -7
- package/lib/transform/db/constraints.js +13 -10
- package/lib/transform/db/expansion.js +7 -3
- package/lib/transform/db/flattening.js +4 -14
- package/lib/transform/db/processSqlServices.js +2 -1
- package/lib/transform/db/temporal.js +5 -7
- package/lib/transform/db/views.js +2 -4
- package/lib/transform/draft/db.js +8 -8
- package/lib/transform/draft/odata.js +10 -7
- package/lib/transform/forOdata.js +10 -5
- package/lib/transform/forRelationalDB.js +5 -75
- package/lib/transform/localized.js +1 -1
- package/lib/transform/odata/createForeignKeys.js +11 -10
- package/lib/transform/odata/flattening.js +8 -4
- package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +96 -0
- package/lib/transform/odata/typesExposure.js +3 -3
- package/lib/transform/transformUtils.js +4 -8
- package/lib/transform/translateAssocsToJoins.js +14 -7
- package/lib/transform/universalCsn/universalCsnEnricher.js +10 -4
- package/lib/utils/objectUtils.js +0 -17
- package/package.json +10 -13
- package/share/messages/def-upcoming-virtual-change.md +1 -1
- package/LICENSE +0 -37
- package/bin/cds_remove_invalid_whitespace.js +0 -138
- package/doc/CHANGELOG_ARCHIVE.md +0 -3604
- package/lib/gen/genericAntlrParser.js +0 -3
- package/lib/gen/language.checksum +0 -1
- package/lib/gen/language.interp +0 -456
- package/lib/gen/language.tokens +0 -180
- package/lib/gen/languageLexer.interp +0 -439
- package/lib/gen/languageLexer.js +0 -1483
- package/lib/gen/languageLexer.tokens +0 -167
- package/lib/gen/languageParser.js +0 -24941
- package/lib/language/antlrParser.js +0 -205
- package/lib/language/errorStrategy.js +0 -646
- package/lib/language/genericAntlrParser.js +0 -1572
- package/lib/parsers/CdlGrammar.g4 +0 -2070
package/lib/gen/BaseParser.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Base class for generated parser, for redepage v0.2.
|
|
1
|
+
// Base class for generated parser, for redepage v0.2.4
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// list of predicates which are tested when continue parsing after error starts,
|
|
10
10
|
// i.e. there is a predicate on the first token to match after recover example
|
|
11
11
|
// `afterBrace` or just method which by default just sets this.conditionTokenIdx
|
|
12
|
-
|
|
12
|
+
// and this.conditionStackLength and returns true?
|
|
13
13
|
|
|
14
14
|
class BaseParser {
|
|
15
15
|
keywords;
|
|
@@ -110,7 +110,7 @@ class BaseParser {
|
|
|
110
110
|
|
|
111
111
|
e() { // error: report and recover
|
|
112
112
|
const la = this.tokens[this.tokenIdx];
|
|
113
|
-
this._trace( 'detect parsing error
|
|
113
|
+
this._trace( 'detect parsing error' );
|
|
114
114
|
if (this.errorTokenIdx === this.tokenIdx)
|
|
115
115
|
throw Error( `Already reported error for ${ tokenFullName( la ) } at ${ la.location }`);
|
|
116
116
|
|
|
@@ -134,7 +134,7 @@ class BaseParser {
|
|
|
134
134
|
this.reportUnexpectedToken_();
|
|
135
135
|
const syncSet = this._calculateTokenSet( 'Y' );
|
|
136
136
|
const recoverDepth = this._findSyncToken( syncSet );
|
|
137
|
-
this._trace( 'recover from error
|
|
137
|
+
this._trace( 'recover from error' );
|
|
138
138
|
this._recoverFromError( recoverDepth );
|
|
139
139
|
return false;
|
|
140
140
|
}
|
|
@@ -181,7 +181,7 @@ class BaseParser {
|
|
|
181
181
|
return true;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
// instead of gi() for `
|
|
184
|
+
// instead of gi() for `Id<greedy>`
|
|
185
185
|
giA( state, follow ) { // go to state (after trying to test again as identifier)
|
|
186
186
|
if (!this.tokens[this.tokenIdx].keyword) // lk() had directly returned the type
|
|
187
187
|
return this.g( state, follow );
|
|
@@ -200,9 +200,7 @@ class BaseParser {
|
|
|
200
200
|
return false; // do not execute action after it
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
// instead of gi() at rule end (RuleEnd_ in follow-set) for `
|
|
204
|
-
// TODO: investigate why this is just used once - should be for all no-`as`
|
|
205
|
-
// cases
|
|
203
|
+
// instead of gi() at rule end (RuleEnd_ in follow-set) for `Id<weak>`, TODO: delete
|
|
206
204
|
giR( state, follow ) { // go to state (after trying to test again as identifier)
|
|
207
205
|
const { keyword } = this.tokens[this.tokenIdx];
|
|
208
206
|
if (!keyword || this.keywords[keyword])
|
|
@@ -227,14 +225,14 @@ class BaseParser {
|
|
|
227
225
|
: this.e();
|
|
228
226
|
}
|
|
229
227
|
|
|
230
|
-
// instead of m() for identifiers via `Id` or `
|
|
228
|
+
// instead of m() for identifiers via `Id` or `Id<weak>`
|
|
231
229
|
mi( state, ident = true ) { // match identifier token
|
|
232
230
|
return (this.tokens[this.tokenIdx].type === 'Id')
|
|
233
231
|
? this.ci( state, ident )
|
|
234
232
|
: this.e();
|
|
235
233
|
}
|
|
236
234
|
|
|
237
|
-
// instead of mi() for `
|
|
235
|
+
// instead of mi() for `Id<greedy>`
|
|
238
236
|
miA( state, ident = true ) { // match identifier token
|
|
239
237
|
return (this.tokens[this.tokenIdx].type === 'Id')
|
|
240
238
|
? this.ciA( state, ident )
|
|
@@ -254,7 +252,7 @@ class BaseParser {
|
|
|
254
252
|
this.s = state;
|
|
255
253
|
this.errorState = state;
|
|
256
254
|
if (this.constructor.tracingParser)
|
|
257
|
-
this._trace( `consume ${ tokenFullName( la, ' as ' ) }
|
|
255
|
+
this._trace( `consume ${ tokenFullName( la, ' as ' ) }`, la );
|
|
258
256
|
return true;
|
|
259
257
|
}
|
|
260
258
|
|
|
@@ -271,7 +269,7 @@ class BaseParser {
|
|
|
271
269
|
return this.c( state, ident )
|
|
272
270
|
}
|
|
273
271
|
|
|
274
|
-
// instead of ci() for `
|
|
272
|
+
// instead of ci() for `Id<greedy>`, used both with l() and lk()
|
|
275
273
|
ciA( state, ident = 'ident' ) { // consume identifier token, the "All" variant
|
|
276
274
|
return this.c( state, ident )
|
|
277
275
|
}
|
|
@@ -286,7 +284,7 @@ class BaseParser {
|
|
|
286
284
|
return this.lP( first2 ) && this.ck( state );
|
|
287
285
|
}
|
|
288
286
|
|
|
289
|
-
// for parser token or token set via `/`
|
|
287
|
+
// for parser token or token set via `/` -> cx() ?
|
|
290
288
|
ckA( state ) {
|
|
291
289
|
// if it really should be considered an Id, `set this.la().parsedAs` yourself
|
|
292
290
|
return this.c( state, (this.l() === 'Id' ? 'keyword' : 'token') );
|
|
@@ -316,7 +314,7 @@ class BaseParser {
|
|
|
316
314
|
}
|
|
317
315
|
// calling the condition might have side effects (precendence conditions have)
|
|
318
316
|
// → call tracing “name” before
|
|
319
|
-
const fail = this[cond](
|
|
317
|
+
const fail = this[cond]( arg, true ); // TODO: use single-letter for run?
|
|
320
318
|
if (this.constructor.tracingParser)
|
|
321
319
|
this._traceSubPush( !fail );
|
|
322
320
|
// The default case must not have actions. If written in grammar with action,
|
|
@@ -379,7 +377,7 @@ class BaseParser {
|
|
|
379
377
|
: ' prematurely');
|
|
380
378
|
const text = immediately ? '⚠ exit rule' : '⏎ exit rule';
|
|
381
379
|
this.s = caller.followState; // for trace
|
|
382
|
-
this._trace( [ text, caller.ruleState, post,
|
|
380
|
+
this._trace( [ text, caller.ruleState, post, 'back to' ] )
|
|
383
381
|
if (immediately && this.stack.at(-1)?.followState != null)
|
|
384
382
|
this.trace = [ this.errorState ]; // show last good state in trace
|
|
385
383
|
}
|
|
@@ -434,13 +432,14 @@ class BaseParser {
|
|
|
434
432
|
if (typeof cmd[0] !== 'number') // don't skip push to state with rule call
|
|
435
433
|
this.s = cmd[1];
|
|
436
434
|
if (cmd[0] !== (lk1 ? 'ck' : 'ci')) { // make the std case fast
|
|
435
|
+
// TODO: also not with lean condition
|
|
437
436
|
let match1 = this._pred_next( 'Id', lk1, 'P' ); // TODO: really P for I?
|
|
438
437
|
if (!match1) {
|
|
439
438
|
if (lk1 || match1 === false) // assert for correct code generation
|
|
440
439
|
throw Error( `Cannot match first prediction token in rule at state ${ saved.s }` );
|
|
441
440
|
if (match1 == null) {
|
|
442
441
|
this._traceSubPush( 0 ); // TODO: make _pred_next push this
|
|
443
|
-
match1 = this._matchesInFollow( 'Id', lk1, 'I' );
|
|
442
|
+
match1 = this._matchesInFollow( 'Id', lk1, 'I' ); // TODO: 'I'?
|
|
444
443
|
}
|
|
445
444
|
else {
|
|
446
445
|
this._traceSubPush( false );
|
|
@@ -471,7 +470,23 @@ class BaseParser {
|
|
|
471
470
|
|
|
472
471
|
// Standard weak-conflict predicate -------------------------------------------
|
|
473
472
|
|
|
473
|
+
/**
|
|
474
|
+
* Return whether current token (its type and keyword are args - TODO delete?)
|
|
475
|
+
* would be matched when starting at the current state:
|
|
476
|
+
* - true/false are definite answers,
|
|
477
|
+
* - null: reached end-of-rule (let caller decide what to do).
|
|
478
|
+
*
|
|
479
|
+
* Changes by side-effect:
|
|
480
|
+
* - this.s
|
|
481
|
+
* - with mode='P' (first step in keyword prediction) if a rule is called:
|
|
482
|
+
* this.stack, this.dynamic_, this.prec_
|
|
483
|
+
*
|
|
484
|
+
* Conditions are only evaluated with mode='M' (expected set in msgs) or if
|
|
485
|
+
* condition is listed in `this.leanConditions`.
|
|
486
|
+
*/
|
|
474
487
|
_pred_next( type, keyword, mode ) { // mode = P | K | I | E | R | M
|
|
488
|
+
// TODO mode: really distinguish between K | I | E | R ?
|
|
489
|
+
// Probably not: would not work with caching? → P, P -> F
|
|
475
490
|
const properCall = (mode === 'P');
|
|
476
491
|
const lean = (mode !== 'M'); // TODO: extra method with conditions ?
|
|
477
492
|
// TODO: if false, use condition in this.leanConditions
|
|
@@ -496,8 +511,9 @@ class BaseParser {
|
|
|
496
511
|
return true;
|
|
497
512
|
case 'ciA': // TODO: fixKeywordTokenIdx ?
|
|
498
513
|
return mode !== 'R';
|
|
499
|
-
// in the R prediction for optional `Id<
|
|
514
|
+
// in the R prediction for optional `Id<weak>` at rule end, only
|
|
500
515
|
// alternative keyword matches are preferred, not identifier matches
|
|
516
|
+
// TODO: delete this prediction
|
|
501
517
|
case 'ci':
|
|
502
518
|
if (!keyword ||
|
|
503
519
|
!this.keywords[keyword] && this.fixKeywordTokenIdx !== this.tokenIdx)
|
|
@@ -564,7 +580,7 @@ class BaseParser {
|
|
|
564
580
|
if (!cond || lean && !this.leanConditions[cond])
|
|
565
581
|
return false;
|
|
566
582
|
if (!this.constructor.tracingParser)
|
|
567
|
-
return !!this[cond](
|
|
583
|
+
return !!this[cond]( cmd[4], mode );
|
|
568
584
|
// TODO: let this[cond]( true ) return recovery badness in error case
|
|
569
585
|
if (!lean) {
|
|
570
586
|
const { traceName } = this[cond];
|
|
@@ -572,12 +588,12 @@ class BaseParser {
|
|
|
572
588
|
// calling the condition might have side effects (precendence conditions have)
|
|
573
589
|
// → call tracing “name” before
|
|
574
590
|
}
|
|
575
|
-
const succeed = !this[cond](
|
|
591
|
+
const succeed = !this[cond]( cmd[4], mode );
|
|
576
592
|
this._traceSubPush( lean ? { true: 'C✔', false: 'C✖' }[succeed] : succeed );
|
|
577
593
|
return !succeed;
|
|
578
594
|
}
|
|
579
595
|
|
|
580
|
-
_matchesInFollow( type, keyword, mode ) { // mode = E | R
|
|
596
|
+
_matchesInFollow( type, keyword, mode ) { // mode = E | R and K | I
|
|
581
597
|
// TODO: now also set stack!
|
|
582
598
|
const savedState = this.s;
|
|
583
599
|
// TODO: caching
|
|
@@ -588,6 +604,7 @@ class BaseParser {
|
|
|
588
604
|
while (match == null && --depth) {
|
|
589
605
|
this.dynamic_ = Object.getPrototypeOf( this.dynamic_ );
|
|
590
606
|
this.s = this.stack[depth].followState;
|
|
607
|
+
// TODO: this.prec_ ?
|
|
591
608
|
match = this._pred_next( type, keyword, mode );
|
|
592
609
|
this._traceSubPush( match == null ? 0 : match === (mode !== 'R') );
|
|
593
610
|
// successfully matching a keyword in giR() means unsuccessful match as
|
|
@@ -700,7 +717,7 @@ class BaseParser {
|
|
|
700
717
|
case 'ci': case 'ciA': case 'mi': case 'miA':
|
|
701
718
|
this.addTokenToSet_( expecting, 'Id', val, false );
|
|
702
719
|
// TODO: should we do s/th special, such that a reserved word is a sync
|
|
703
|
-
// token for Id<
|
|
720
|
+
// token for Id<greedy>? Probably not, see also comment in
|
|
704
721
|
// _findSyncToken()
|
|
705
722
|
break loop;
|
|
706
723
|
case 'g': case 'gi': case 'e':
|
|
@@ -747,7 +764,7 @@ class BaseParser {
|
|
|
747
764
|
else if (set[type] === true && !(keyword && this.keywords[keyword]))
|
|
748
765
|
delete set[type]; // delete Id if Id token or non-reserved keyword
|
|
749
766
|
|
|
750
|
-
this._trace( 'collect tokens for message
|
|
767
|
+
this._trace( 'collect tokens for message' );
|
|
751
768
|
const { trace } = this;
|
|
752
769
|
const saved = this._saveForWalk();
|
|
753
770
|
const expecting = Object.keys( set )
|
|
@@ -765,16 +782,18 @@ class BaseParser {
|
|
|
765
782
|
this.recoverTokenIdx = this.tokenIdx;
|
|
766
783
|
while (this.recoverTokenIdx <= this.eofIndex) {
|
|
767
784
|
const { keyword, type } = this.tokens[this.recoverTokenIdx];
|
|
768
|
-
|
|
769
|
-
if (
|
|
770
|
-
return
|
|
771
|
-
|
|
785
|
+
let recoverDepth = keyword ? syncSet[keyword] : null;
|
|
786
|
+
if (recoverDepth != null)
|
|
787
|
+
return recoverDepth;
|
|
788
|
+
recoverDepth = syncSet[type];
|
|
772
789
|
// sync to Id only if in expected set of last good state or if after ';'
|
|
773
|
-
if (
|
|
790
|
+
if (recoverDepth != null &&
|
|
774
791
|
(type !== 'Id' || (!keyword || !this.keywords[keyword]) &&
|
|
775
792
|
// reserved words do not match Id in expected-set
|
|
776
|
-
(
|
|
777
|
-
|
|
793
|
+
(recoverDepth > rewindDepth || this.tokens[this.recoverTokenIdx - 1].type === ';')))
|
|
794
|
+
// if (recoverDepth != null &&
|
|
795
|
+
// (this.recoverTokenIdx > this.tokenIdx ||
|
|
796
|
+
return recoverDepth;
|
|
778
797
|
++this.recoverTokenIdx;
|
|
779
798
|
}
|
|
780
799
|
throw Error( 'EOF must be last in `tokens`' );
|
|
@@ -809,7 +828,7 @@ class BaseParser {
|
|
|
809
828
|
|
|
810
829
|
_skipErrorTokens() {
|
|
811
830
|
if (this.constructor.tracingParser && this.tokenIdx <= this.recoverTokenIdx) {
|
|
812
|
-
this._trace( `
|
|
831
|
+
this._trace( `skip ${ this.recoverTokenIdx - this.tokenIdx } tokens to recover from error`,
|
|
813
832
|
this.tokens[this.recoverTokenIdx] );
|
|
814
833
|
}
|
|
815
834
|
while (this.tokenIdx < this.recoverTokenIdx)
|
|
@@ -832,7 +851,7 @@ class BaseParser {
|
|
|
832
851
|
msg ??= `Unexpected token ${ tokenFullName( token, ': ' ) }`;
|
|
833
852
|
this.reportError_(
|
|
834
853
|
token.location, msg + ' - expecting: ' +
|
|
835
|
-
this.expectingArray_().map( tokenName ).sort().join( ',' ) );
|
|
854
|
+
this.expectingArray_().map( tokenName ).sort().join( ', ' ) );
|
|
836
855
|
}
|
|
837
856
|
|
|
838
857
|
reportReservedWord_() {
|
|
@@ -875,7 +894,7 @@ class BaseParser {
|
|
|
875
894
|
this.log( indent, line, `(${ la })` );
|
|
876
895
|
return;
|
|
877
896
|
}
|
|
878
|
-
else if (la === 2) {
|
|
897
|
+
else if (la === 2) { // confirming tokens in expected set
|
|
879
898
|
this.log( indent, ' ', msg + ':',
|
|
880
899
|
this.trace.map( traceStep ).join( ' → ' ) );
|
|
881
900
|
this.trace = [ this.s ?? '⚠' ];
|
|
@@ -887,31 +906,23 @@ class BaseParser {
|
|
|
887
906
|
this.trace = [ -1 ];
|
|
888
907
|
}
|
|
889
908
|
this.trace.push( this.s ?? '⚠' );
|
|
890
|
-
if (Array.isArray( msg )) {
|
|
891
|
-
const [ intro, state, finale,
|
|
892
|
-
let depth = (exitLength) ? exitLength - 1 : this.stack.length + 1;
|
|
893
|
-
let length = this.trace.length - 1;
|
|
894
|
-
this.trace[length] = `${ this.trace[length] }(${ depth })`;
|
|
895
|
-
depth = exitLength || this.stack.length;
|
|
896
|
-
while (length && typeof this.trace[--length] !== 'number')
|
|
897
|
-
;
|
|
898
|
-
this.trace[length] = `${ this.trace[length] }(${ depth })`;
|
|
899
|
-
|
|
909
|
+
if (Array.isArray( msg )) { // rule call and exit
|
|
910
|
+
const [ intro, state, finale, exit ] = msg;
|
|
900
911
|
let start = state;
|
|
901
912
|
while (typeof this.table[--start] !== 'string')
|
|
902
913
|
;
|
|
903
|
-
const post = (
|
|
904
|
-
msg = `${ intro } “${ this.table[start] }”${ post || '' }
|
|
914
|
+
const post = (exit || start + 1 < state) && finale;
|
|
915
|
+
msg = `${ intro } “${ this.table[start] }”${ post || '' } ${ exit || 'from' } stack level ${ this.stack.length }`;
|
|
905
916
|
}
|
|
906
917
|
// Yes, I know util.format, but do not want to have a `require` in this file
|
|
907
918
|
const line = location.line < 1e5 ? ` ${ location.line }`.slice(-5) : `${ location.line }`;
|
|
908
919
|
const col = location.col < 1e4 ? `:${ location.col } `.slice(0,5) : `:${location.col }`;
|
|
909
|
-
this.log( line + col + indent + msg,
|
|
910
|
-
|
|
920
|
+
this.log( line + col + indent + msg + ', states:',
|
|
921
|
+
this.trace.map( traceStep ).join( ' → ' ) );
|
|
911
922
|
this.trace = [ this.s ?? '⚠' ];
|
|
912
923
|
}
|
|
913
924
|
|
|
914
|
-
inSameRule_( lowState, highState ) {
|
|
925
|
+
inSameRule_( lowState = this.s, highState = this.stack.at(-1).followState ) {
|
|
915
926
|
if (lowState > highState)
|
|
916
927
|
[ lowState, highState ] = [ highState, lowState ];
|
|
917
928
|
while (lowState < highState) {
|
|
@@ -923,24 +934,24 @@ class BaseParser {
|
|
|
923
934
|
|
|
924
935
|
// Predefined conditions with extra option names:
|
|
925
936
|
|
|
926
|
-
hide_( mode ) {
|
|
937
|
+
hide_( _arg, mode ) {
|
|
927
938
|
return mode === 'M';
|
|
928
939
|
}
|
|
929
|
-
precLeft_(
|
|
940
|
+
precLeft_( prec ) { // <prec=…>, <…,assoc=left>, <…,prefix=once>
|
|
930
941
|
const parentPrec = this.stack.at( -1 ).prec;
|
|
931
942
|
if (parentPrec != null && parentPrec >= prec)
|
|
932
943
|
return true;
|
|
933
944
|
this.prec_ = prec;
|
|
934
945
|
return false;
|
|
935
946
|
}
|
|
936
|
-
precRight_(
|
|
947
|
+
precRight_( prec ) { // <…,assoc=right>, <…,prefix>
|
|
937
948
|
const parentPrec = this.stack.at( -1 ).prec;
|
|
938
949
|
if (parentPrec != null && parentPrec >= prec)
|
|
939
950
|
return true;
|
|
940
951
|
this.prec_ = prec - 1;
|
|
941
952
|
return false;
|
|
942
953
|
}
|
|
943
|
-
precNone_(
|
|
954
|
+
precNone_( prec ) { // <…,assoc=none>, <…,postfix=once>
|
|
944
955
|
const parentPrec = this.stack.at( -1 ).prec;
|
|
945
956
|
if (parentPrec != null && parentPrec >= prec ||
|
|
946
957
|
this.prec_ != null && this.prec_ <= prec)
|
|
@@ -948,7 +959,7 @@ class BaseParser {
|
|
|
948
959
|
this.prec_ = prec;
|
|
949
960
|
return false;
|
|
950
961
|
}
|
|
951
|
-
precPost_(
|
|
962
|
+
precPost_( prec ) { // <…,postfix>
|
|
952
963
|
const parentPrec = this.stack.at( -1 ).prec;
|
|
953
964
|
if (parentPrec != null && parentPrec >= prec ||
|
|
954
965
|
this.prec_ != null && this.prec_ < prec)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
eb778bab22f4006cfcf64e418dcae71c
|