@@ -1134,6 +1134,9 @@ module ts {
1134
1134
InMultiLineCommentTrivia ,
1135
1135
InSingleQuoteStringLiteral ,
1136
1136
InDoubleQuoteStringLiteral ,
1137
+ InTemplateHeadLiteral , // this could also be a NoSubstitutionTemplateLiteral
1138
+ InTemplateMiddleLiteral , //this could also be a TemplateTail
1139
+ InTemplateSubstitutionPosition ,
1137
1140
}
1138
1141
1139
1142
export enum TokenClass {
@@ -5472,12 +5475,12 @@ module ts {
5472
5475
// if there are more cases we want the classifier to be better at.
5473
5476
return true ;
5474
5477
}
5475
-
5476
- // 'classifyKeywordsInGenerics' should be 'true' when a syntactic classifier is not present.
5477
- function getClassificationsForLine ( text : string , lexState : EndOfLineState , classifyKeywordsInGenerics ?: boolean ) : ClassificationResult {
5478
+
5479
+ function getClassificationsForLine ( text : string , lexState : EndOfLineState , syntacticClassifierAbsent ?: boolean ) : ClassificationResult {
5478
5480
var offset = 0 ;
5479
5481
var token = SyntaxKind . Unknown ;
5480
5482
var lastNonTriviaToken = SyntaxKind . Unknown ;
5483
+ var templateStack : SyntaxKind [ ] ;
5481
5484
5482
5485
// If we're in a string literal, then prepend: "\
5483
5486
// (and a newline). That way when we lex we'll think we're still in a string literal.
@@ -5497,6 +5500,21 @@ module ts {
5497
5500
text = "/*\n" + text ;
5498
5501
offset = 3 ;
5499
5502
break ;
5503
+ case EndOfLineState . InTemplateHeadLiteral :
5504
+ if ( syntacticClassifierAbsent ) {
5505
+ text = "`\n" + text ;
5506
+ offset = 2 ;
5507
+ }
5508
+ break ;
5509
+ case EndOfLineState . InTemplateMiddleLiteral :
5510
+ if ( syntacticClassifierAbsent ) {
5511
+ text = "${\n" + text ;
5512
+ offset = 3 ;
5513
+ }
5514
+ // fallthrough
5515
+ case EndOfLineState . InTemplateSubstitutionPosition :
5516
+ templateStack = [ SyntaxKind . TemplateHead ] ;
5517
+ break ;
5500
5518
}
5501
5519
5502
5520
scanner . setText ( text ) ;
@@ -5558,16 +5576,54 @@ module ts {
5558
5576
angleBracketStack -- ;
5559
5577
}
5560
5578
else if ( token === SyntaxKind . AnyKeyword ||
5561
- token === SyntaxKind . StringKeyword ||
5562
- token === SyntaxKind . NumberKeyword ||
5563
- token === SyntaxKind . BooleanKeyword ) {
5564
- if ( angleBracketStack > 0 && ! classifyKeywordsInGenerics ) {
5579
+ token === SyntaxKind . StringKeyword ||
5580
+ token === SyntaxKind . NumberKeyword ||
5581
+ token === SyntaxKind . BooleanKeyword ) {
5582
+ if ( angleBracketStack > 0 && ! syntacticClassifierAbsent ) {
5565
5583
// If it looks like we're could be in something generic, don't classify this
5566
5584
// as a keyword. We may just get overwritten by the syntactic classifier,
5567
5585
// causing a noisy experience for the user.
5568
5586
token = SyntaxKind . Identifier ;
5569
5587
}
5570
5588
}
5589
+ else if ( token === SyntaxKind . TemplateHead && syntacticClassifierAbsent ) {
5590
+ if ( ! templateStack ) {
5591
+ templateStack = [ token ] ;
5592
+ }
5593
+ else {
5594
+ templateStack . push ( token ) ;
5595
+ }
5596
+ }
5597
+ else if ( token === SyntaxKind . OpenBraceToken && syntacticClassifierAbsent ) {
5598
+ // If we don't have anything on the template stack,
5599
+ // then we aren't trying to keep track of a previously scanned template head.
5600
+ if ( templateStack && templateStack . length > 0 ) {
5601
+ templateStack . push ( token ) ;
5602
+ }
5603
+ }
5604
+ else if ( token === SyntaxKind . CloseBraceToken && syntacticClassifierAbsent ) {
5605
+ // If we don't have anything on the template stack,
5606
+ // then we aren't trying to keep track of a previously scanned template head.
5607
+ if ( templateStack && templateStack . length > 0 ) {
5608
+ var lastTemplateStackToken = lastOrUndefined ( templateStack ) ;
5609
+
5610
+ if ( lastTemplateStackToken === SyntaxKind . TemplateHead ) {
5611
+ token = scanner . reScanTemplateToken ( ) ;
5612
+
5613
+ // Only pop on a TemplateTail; a TemplateMiddle indicates there is more for us.
5614
+ if ( token === SyntaxKind . TemplateTail ) {
5615
+ templateStack . pop ( ) ;
5616
+ }
5617
+ else {
5618
+ Debug . assert ( token === SyntaxKind . TemplateMiddle , "Should have been a template middle. Was " + token ) ;
5619
+ }
5620
+ }
5621
+ else {
5622
+ Debug . assert ( token === SyntaxKind . CloseBraceToken , "Should have been an open brace. Was: " + token ) ;
5623
+ templateStack . pop ( ) ;
5624
+ }
5625
+ }
5626
+ }
5571
5627
5572
5628
lastNonTriviaToken = token ;
5573
5629
}
@@ -5582,7 +5638,7 @@ module ts {
5582
5638
var start = scanner . getTokenPos ( ) ;
5583
5639
var end = scanner . getTextPos ( ) ;
5584
5640
5585
- addResult ( end - start , classFromKind ( token ) ) ;
5641
+ addResult ( end - start , classFromKind ( token , syntacticClassifierAbsent ) ) ;
5586
5642
5587
5643
if ( end >= text . length ) {
5588
5644
if ( token === SyntaxKind . StringLiteral ) {
@@ -5611,6 +5667,19 @@ module ts {
5611
5667
result . finalLexState = EndOfLineState . InMultiLineCommentTrivia ;
5612
5668
}
5613
5669
}
5670
+ else if ( isTemplateLiteralKind ( token ) && syntacticClassifierAbsent ) {
5671
+ if ( scanner . isUnterminated ( ) ) {
5672
+ if ( token === SyntaxKind . TemplateMiddle ) {
5673
+ result . finalLexState = EndOfLineState . InTemplateMiddleLiteral ;
5674
+ }
5675
+ else {
5676
+ result . finalLexState = EndOfLineState . InTemplateHeadLiteral ;
5677
+ }
5678
+ }
5679
+ }
5680
+ else if ( templateStack && templateStack . length > 0 && lastOrUndefined ( templateStack ) === SyntaxKind . TemplateHead ) {
5681
+ result . finalLexState = EndOfLineState . InTemplateSubstitutionPosition ;
5682
+ }
5614
5683
}
5615
5684
}
5616
5685
@@ -5688,7 +5757,7 @@ module ts {
5688
5757
return token >= SyntaxKind . FirstKeyword && token <= SyntaxKind . LastKeyword ;
5689
5758
}
5690
5759
5691
- function classFromKind ( token : SyntaxKind ) {
5760
+ function classFromKind ( token : SyntaxKind , syntacticClassifierAbsent ?: boolean ) {
5692
5761
if ( isKeyword ( token ) ) {
5693
5762
return TokenClass . Keyword ;
5694
5763
}
@@ -5714,6 +5783,10 @@ module ts {
5714
5783
return TokenClass . Whitespace ;
5715
5784
case SyntaxKind . Identifier :
5716
5785
default :
5786
+ // Only give a classification if nothing will more accurately classify.
5787
+ if ( syntacticClassifierAbsent && isTemplateLiteralKind ( token ) ) {
5788
+ return TokenClass . StringLiteral ; // should make a TemplateLiteral
5789
+ }
5717
5790
return TokenClass . Identifier ;
5718
5791
}
5719
5792
}
0 commit comments