@@ -56,7 +56,7 @@ struct ParserTraits<char> : public ParserTraitsBase<>
56
56
{
57
57
static std::regex GetRoughTokenizer ()
58
58
{
59
- return std::regex (R"( (\{\{)|(\}\})|(\{%)|(%\})|(\{#)|(#\})|(\n))" );
59
+ return std::regex (R"( (\{\{)|(\}\})|(\{%[\+\-]?\s+raw\s+[\+\-]?%\})|(\{%[\+\-]?\s+endraw\s+[\+\-]?%\})|(\{% )|(%\})|(\{#)|(#\})|(\n))" );
60
60
}
61
61
static std::regex GetKeywords ()
62
62
{
@@ -112,7 +112,7 @@ struct ParserTraits<wchar_t> : public ParserTraitsBase<>
112
112
{
113
113
static std::wregex GetRoughTokenizer ()
114
114
{
115
- return std::wregex (LR"( (\{\{)|(\}\})|(\{%)|(%\})|(\{#)|(#\})|(\n))" );
115
+ return std::wregex (LR"( (\{\{)|(\}\})|(\{%[\+\-]?\s+raw\s+[\+\-]?%\})|(\{%[\+\-]?\s+endraw\s+[\+\-]?%\})|(\{% )|(%\})|(\{#)|(#\})|(\n))" );
116
116
}
117
117
static std::wregex GetKeywords ()
118
118
{
@@ -289,6 +289,8 @@ class TemplateParser : public LexerHelper
289
289
RM_Unknown = 0 ,
290
290
RM_ExprBegin = 1 ,
291
291
RM_ExprEnd,
292
+ RM_RawBegin,
293
+ RM_RawEnd,
292
294
RM_StmtBegin,
293
295
RM_StmtEnd,
294
296
RM_CommentBegin,
@@ -308,7 +310,8 @@ class TemplateParser : public LexerHelper
308
310
Expression,
309
311
Statement,
310
312
Comment,
311
- LineStatement
313
+ LineStatement,
314
+ RawBlock
312
315
};
313
316
314
317
struct TextBlockInfo
@@ -352,6 +355,14 @@ class TemplateParser : public LexerHelper
352
355
}
353
356
} while (matchBegin != matchEnd);
354
357
FinishCurrentLine (m_template->size ());
358
+
359
+ if ( m_currentBlockInfo.type == TextBlockType::RawBlock)
360
+ {
361
+ nonstd::expected<void , ParseError> result = MakeParseError (ErrorCode::ExpectedRawEnd, MakeToken (Token::RawEnd, {m_template->size (), m_template->size () }));
362
+ foundErrors.push_back (result.error ());
363
+ return nonstd::make_unexpected (std::move (foundErrors));
364
+ }
365
+
355
366
FinishCurrentBlock (m_template->size ());
356
367
357
368
if (!foundErrors.empty ())
@@ -395,6 +406,8 @@ class TemplateParser : public LexerHelper
395
406
}
396
407
break ;
397
408
case RM_CommentBegin:
409
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock)
410
+ break ;
398
411
if (m_currentBlockInfo.type != TextBlockType::RawText)
399
412
{
400
413
FinishCurrentLine (match.position () + 2 );
@@ -407,6 +420,8 @@ class TemplateParser : public LexerHelper
407
420
break ;
408
421
409
422
case RM_CommentEnd:
423
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock)
424
+ break ;
410
425
if (m_currentBlockInfo.type != TextBlockType::Comment)
411
426
{
412
427
FinishCurrentLine (match.position () + 2 );
@@ -444,6 +459,26 @@ class TemplateParser : public LexerHelper
444
459
445
460
m_currentBlockInfo.range .startOffset = FinishCurrentBlock (matchStart);
446
461
break ;
462
+ case RM_RawBegin:
463
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock)
464
+ break ;
465
+ else if (m_currentBlockInfo.type != TextBlockType::RawText && m_currentBlockInfo.type != TextBlockType::Comment)
466
+ {
467
+ FinishCurrentLine (match.position () + match.length ());
468
+ return MakeParseError (ErrorCode::UnexpectedRawBegin, MakeToken (Token::RawBegin, {matchStart, matchStart + match.length ()}));
469
+ }
470
+ StartControlBlock (TextBlockType::RawBlock, matchStart);
471
+ break ;
472
+ case RM_RawEnd:
473
+ if (m_currentBlockInfo.type == TextBlockType::Comment)
474
+ break ;
475
+ else if (m_currentBlockInfo.type != TextBlockType::RawBlock)
476
+ {
477
+ FinishCurrentLine (match.position () + match.length ());
478
+ return MakeParseError (ErrorCode::UnexpectedRawEnd, MakeToken (Token::RawEnd, {matchStart, matchStart + match.length ()}));
479
+ }
480
+ m_currentBlockInfo.range .startOffset = FinishCurrentBlock (matchStart);
481
+ break ;
447
482
}
448
483
449
484
return nonstd::expected<void , ParseError>();
@@ -453,7 +488,7 @@ class TemplateParser : public LexerHelper
453
488
{
454
489
size_t startOffset = matchStart + 2 ;
455
490
size_t endOffset = matchStart;
456
- if (m_currentBlockInfo.type != TextBlockType::RawText)
491
+ if (m_currentBlockInfo.type != TextBlockType::RawText || m_currentBlockInfo. type == TextBlockType::RawBlock )
457
492
return ;
458
493
else
459
494
endOffset = StripBlockLeft (m_currentBlockInfo, startOffset, endOffset);
@@ -465,8 +500,53 @@ class TemplateParser : public LexerHelper
465
500
(*m_template)[startOffset] == ' -' )
466
501
++ startOffset;
467
502
}
468
- m_currentBlockInfo. range . startOffset = startOffset;
503
+
469
504
m_currentBlockInfo.type = blockType;
505
+
506
+ if (blockType==TextBlockType::RawBlock)
507
+ startOffset = StripBlockRight (m_currentBlockInfo, matchStart);
508
+
509
+ m_currentBlockInfo.range .startOffset = startOffset;
510
+ }
511
+
512
+ size_t StripBlockRight (TextBlockInfo& currentBlockInfo, size_t position)
513
+ {
514
+ bool doTrim = m_settings.trimBlocks && (m_currentBlockInfo.type == TextBlockType::Statement || m_currentBlockInfo.type == TextBlockType::RawBlock);
515
+
516
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock)
517
+ {
518
+ position+=2 ;
519
+ for (; position < m_template->size (); ++ position)
520
+ {
521
+ if (' %' == (*m_template)[position])
522
+ break ;
523
+ }
524
+ }
525
+
526
+ size_t newPos = position + 2 ;
527
+
528
+ if ((m_currentBlockInfo.type != TextBlockType::RawText) && position != 0 )
529
+ {
530
+ auto ctrlChar = (*m_template)[position - 1 ];
531
+ doTrim = ctrlChar == ' -' ? true : (ctrlChar == ' +' ? false : doTrim);
532
+ }
533
+
534
+ if (doTrim)
535
+ {
536
+ auto locale = std::locale ();
537
+ for (;newPos < m_template->size (); ++ newPos)
538
+ {
539
+ auto ch = (*m_template)[newPos];
540
+ if (ch == ' \n ' )
541
+ {
542
+ ++ newPos;
543
+ break ;
544
+ }
545
+ if (!std::isspace (ch, locale))
546
+ break ;
547
+ }
548
+ }
549
+ return newPos;
470
550
}
471
551
472
552
size_t StripBlockLeft (TextBlockInfo& currentBlockInfo, size_t ctrlCharPos, size_t endOffset)
@@ -483,7 +563,7 @@ class TemplateParser : public LexerHelper
483
563
484
564
doStrip |= doTotalStrip;
485
565
}
486
- if (!doStrip || currentBlockInfo.type != TextBlockType::RawText)
566
+ if (!doStrip || ( currentBlockInfo.type != TextBlockType::RawText && currentBlockInfo. type != TextBlockType::RawBlock) )
487
567
return endOffset;
488
568
489
569
auto locale = std::locale ();
@@ -512,6 +592,7 @@ class TemplateParser : public LexerHelper
512
592
513
593
switch (block.type )
514
594
{
595
+ case TextBlockType::RawBlock:
515
596
case TextBlockType::RawText:
516
597
{
517
598
if (block.range .size () == 0 )
@@ -648,32 +729,25 @@ class TemplateParser : public LexerHelper
648
729
649
730
size_t FinishCurrentBlock (size_t position)
650
731
{
651
- bool doTrim = m_settings.trimBlocks && m_currentBlockInfo.type == TextBlockType::Statement;
652
- size_t newPos = position + 2 ;
732
+ size_t newPos;
653
733
654
- if (( m_currentBlockInfo.type != TextBlockType::RawText) && position != 0 )
734
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock )
655
735
{
656
- auto ctrlChar = (*m_template)[position - 1 ];
657
- doTrim = ctrlChar == ' -' ? true : (ctrlChar == ' +' ? false : doTrim);
658
- if (ctrlChar == ' +' || ctrlChar == ' -' )
659
- -- position;
736
+ size_t currentPosition = position;
737
+ position = StripBlockLeft (m_currentBlockInfo, currentPosition+2 , currentPosition);
738
+ newPos = StripBlockRight (m_currentBlockInfo, currentPosition);
660
739
}
661
-
662
- if (doTrim)
740
+ else
663
741
{
664
- auto locale = std::locale ( );
665
- for (;newPos < m_template-> size (); ++ newPos )
742
+ newPos = StripBlockRight (m_currentBlockInfo, position );
743
+ if ((m_currentBlockInfo. type != TextBlockType::RawText) && position != 0 )
666
744
{
667
- auto ch = (*m_template)[newPos];
668
- if (ch == ' \n ' )
669
- {
670
- ++ newPos;
671
- break ;
672
- }
673
- if (!std::isspace (ch, locale))
674
- break ;
745
+ auto ctrlChar = (*m_template)[position - 1 ];
746
+ if (ctrlChar == ' +' || ctrlChar == ' -' )
747
+ -- position;
675
748
}
676
749
}
750
+
677
751
m_currentBlockInfo.range .endOffset = position;
678
752
m_textBlocks.push_back (m_currentBlockInfo);
679
753
m_currentBlockInfo.type = TextBlockType::RawText;
@@ -928,6 +1002,8 @@ std::unordered_map<int, MultiStringLiteral> ParserTraitsBase<T>::s_tokens = {
928
1002
{Token::From, UNIVERSAL_STR (" form" )},
929
1003
{Token::As, UNIVERSAL_STR (" as" )},
930
1004
{Token::Do, UNIVERSAL_STR (" do" )},
1005
+ {Token::RawBegin, UNIVERSAL_STR (" {% raw %}" )},
1006
+ {Token::RawEnd, UNIVERSAL_STR (" {% endraw %}" )},
931
1007
{Token::CommentBegin, UNIVERSAL_STR (" {#" )},
932
1008
{Token::CommentEnd, UNIVERSAL_STR (" #}" )},
933
1009
{Token::StmtBegin, UNIVERSAL_STR (" {%" )},
0 commit comments