From 42f712ece7e33f5613b43a6fc28d87c4184fe7bf Mon Sep 17 00:00:00 2001 From: Daniel Marcotte Date: Mon, 30 Mar 2015 13:51:55 -0700 Subject: [PATCH] Support for raw block helpers See https://github.com/wycats/handlebars.js/pull/730 --- .../handlebars/parsing/_HbLexer.java | 470 ++++++++++-------- .../handlebars/parsing/HbParsing.java | 67 ++- .../handlebars/parsing/HbTokenTypes.java | 3 + .../handlebars/parsing/handlebars.flex | 29 +- .../inspections/afterWrongOpenRawBlock.hbs | 4 + .../inspections/beforeWrongOpenRawBlock.hbs | 4 + handlebars/test/data/parser/RawBlock.hbs | 1 + handlebars/test/data/parser/RawBlock.txt | 23 + .../test/data/parser/RawBlockParameters.hbs | 1 + .../test/data/parser/RawBlockParameters.txt | 35 ++ .../inspections/HbBlockMismatchFixTest.java | 4 + .../parsing/HbLexerFreeFormTest.java | 12 +- .../parsing/HbParserFreeFormTest.java | 8 + 13 files changed, 437 insertions(+), 224 deletions(-) create mode 100644 handlebars/test/data/inspections/afterWrongOpenRawBlock.hbs create mode 100644 handlebars/test/data/inspections/beforeWrongOpenRawBlock.hbs create mode 100644 handlebars/test/data/parser/RawBlock.hbs create mode 100644 handlebars/test/data/parser/RawBlock.txt create mode 100644 handlebars/test/data/parser/RawBlockParameters.hbs create mode 100644 handlebars/test/data/parser/RawBlockParameters.txt diff --git a/handlebars/gen/com/dmarcotte/handlebars/parsing/_HbLexer.java b/handlebars/gen/com/dmarcotte/handlebars/parsing/_HbLexer.java index 97995ad747b..19293432a39 100644 --- a/handlebars/gen/com/dmarcotte/handlebars/parsing/_HbLexer.java +++ b/handlebars/gen/com/dmarcotte/handlebars/parsing/_HbLexer.java @@ -1,9 +1,9 @@ -/* The following code was generated by JFlex 1.4.3 on 12/3/14 5:43 PM */ +/* The following code was generated by JFlex 1.4.3 on 3/29/15 1:52 PM */ // We base our lexer directly on the official handlebars.l lexer definition, // making some modifications to account for Jison/JFlex syntax and functionality differences // -// Revision ported: https://github.com/wycats/handlebars.js/commit/58a0b4f17d5338793c92cf4d104e9c44cc485c5b#src/handlebars.l +// Revision ported: https://github.com/wycats/handlebars.js/blob/14b7ef9066d107dc83deedc8e6791947811cc764/src/handlebars.l package com.dmarcotte.handlebars.parsing; @@ -17,21 +17,23 @@ /** * This class is a scanner generated by * JFlex 1.4.3 - * on 12/3/14 5:43 PM from the specification file + * on 3/29/15 1:52 PM from the specification file + * handlebars.flex */ final class _HbLexer implements FlexLexer { /** initial size of the lookahead buffer */ private static final int ZZ_BUFFERSIZE = 16384; /** lexical states */ - public static final int mu = 2; public static final int comment_end = 12; - public static final int comment_block = 10; - public static final int emu = 4; - public static final int YYINITIAL = 0; - public static final int par = 6; public static final int data = 14; public static final int comment = 8; + public static final int par = 6; + public static final int YYINITIAL = 0; + public static final int comment_block = 10; + public static final int raw = 16; + public static final int emu = 4; + public static final int mu = 2; /** * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l @@ -40,19 +42,20 @@ final class _HbLexer implements FlexLexer { * l is of the form l = 2*k, k a non negative integer */ private static final int ZZ_LEXSTATE[] = { - 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 3, 3 + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 3, 3, + 7, 7 }; /** * Translates characters to character classes */ private static final String ZZ_CMAP_PACKED = - "\11\0\1\1\1\2\1\22\1\1\1\1\22\0\1\1\1\15\1\23"+ - "\1\11\1\0\1\37\1\14\1\24\1\5\1\6\3\37\1\16\1\20"+ - "\1\12\12\36\1\0\2\37\1\17\1\10\1\0\1\25\32\0\1\40"+ - "\1\4\1\41\1\13\1\0\1\37\1\35\3\0\1\26\1\34\5\0"+ - "\1\27\5\0\1\32\1\30\1\31\1\33\5\0\1\3\1\37\1\21"+ - "\1\7\uff81\0"; + "\11\0\1\1\1\2\1\22\1\1\1\1\22\0\1\1\1\16\1\23"+ + "\1\13\1\0\1\37\1\15\1\24\1\6\1\7\3\37\1\17\1\21"+ + "\1\5\12\36\1\0\2\37\1\20\1\12\1\0\1\25\32\0\1\40"+ + "\1\4\1\41\1\14\1\0\1\37\1\35\3\0\1\26\1\34\5\0"+ + "\1\27\5\0\1\32\1\30\1\31\1\33\5\0\1\3\1\37\1\10"+ + "\1\11\uff81\0"; /** * Translates characters to character classes @@ -65,18 +68,20 @@ final class _HbLexer implements FlexLexer { private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\1\1\1\2\2\0\1\3\1\4\1\0\1\1\1\5"+ - "\1\2\2\5\1\6\1\7\1\5\1\10\1\5\1\11"+ - "\1\10\3\5\1\12\5\5\1\2\1\5\1\13\2\3"+ - "\1\4\2\5\1\14\1\0\1\15\1\16\2\0\1\17"+ - "\1\20\1\0\1\21\2\0\1\22\5\0\1\23\1\15"+ - "\1\0\1\24\1\3\1\25\1\4\1\0\1\25\1\14"+ - "\1\26\1\16\1\27\1\30\1\31\1\32\1\16\1\33"+ - "\1\21\1\0\1\34\4\0\1\24\2\35\1\4\5\0"+ - "\1\36\1\37\1\40\1\41\1\42\1\0\1\36\1\43"; + "\1\1\1\2\2\0\1\3\1\4\1\0\2\1\1\5"+ + "\1\2\2\5\1\6\1\7\1\10\3\5\1\11\1\6"+ + "\2\5\1\12\5\5\1\2\1\5\1\13\2\3\1\4"+ + "\2\5\1\1\1\14\1\0\1\15\1\16\1\17\3\0"+ + "\1\20\1\21\2\0\1\22\5\0\1\23\1\15\1\0"+ + "\1\24\1\3\1\25\1\4\1\25\1\0\1\1\1\14"+ + "\1\26\1\27\1\16\1\30\1\31\1\32\1\16\1\33"+ + "\1\34\1\0\1\17\4\0\1\24\2\35\1\4\1\0"+ + "\1\1\1\36\1\26\1\0\1\37\1\34\3\0\1\40"+ + "\1\41\1\1\1\42\1\43\1\44\1\45\1\0\1\40"+ + "\1\46\1\47"; private static int [] zzUnpackAction() { - int [] result = new int[96]; + int [] result = new int[107]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -102,20 +107,22 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { private static final String ZZ_ROWMAP_PACKED_0 = "\0\0\0\42\0\104\0\146\0\210\0\252\0\314\0\356"+ - "\0\u0110\0\u0132\0\u0154\0\u0176\0\u0176\0\u0176\0\u0198\0\u0176"+ - "\0\u01ba\0\u0176\0\u01dc\0\u01fe\0\u0220\0\u0242\0\u0176\0\u0264"+ - "\0\u0286\0\u02a8\0\u02ca\0\u02ec\0\u030e\0\u0330\0\u0176\0\u0352"+ - "\0\u0374\0\u0396\0\u03b8\0\u03da\0\u03fc\0\u0110\0\u0176\0\u041e"+ - "\0\u0440\0\u02ca\0\u0176\0\u0176\0\u0462\0\u0484\0\u0220\0\u04a6"+ - "\0\u0176\0\u0242\0\u04c8\0\u04ea\0\u050c\0\u052e\0\u0176\0\u0550"+ - "\0\u02ec\0\u0572\0\u0594\0\u05b6\0\u05d8\0\u05fa\0\u0176\0\u0176"+ - "\0\u0176\0\u061c\0\u0176\0\u0176\0\u0176\0\u0176\0\u0176\0\u063e"+ - "\0\u0176\0\u0484\0\u0176\0\u0660\0\u0682\0\u06a4\0\u06c6\0\u06e8"+ - "\0\u05b6\0\u0176\0\u070a\0\u03da\0\u072c\0\u074e\0\u0770\0\u0792"+ - "\0\u07b4\0\u0176\0\u0176\0\u0176\0\u0176\0\u07d6\0\u0176\0\u0176"; + "\0\u0110\0\u0132\0\u0154\0\u0176\0\u0198\0\u0198\0\u0198\0\u0198"+ + "\0\u01ba\0\u01dc\0\u01fe\0\u0198\0\u0220\0\u0242\0\u0264\0\u0198"+ + "\0\u0286\0\u02a8\0\u02ca\0\u02ec\0\u030e\0\u0330\0\u0352\0\u0198"+ + "\0\u0374\0\u0396\0\u03b8\0\u03da\0\u03fc\0\u041e\0\u0440\0\u0132"+ + "\0\u0198\0\u0462\0\u0484\0\u04a6\0\u04c8\0\u02ec\0\u0198\0\u0198"+ + "\0\u0242\0\u04ea\0\u0198\0\u0264\0\u050c\0\u052e\0\u0550\0\u0572"+ + "\0\u0198\0\u0594\0\u030e\0\u05b6\0\u05d8\0\u05fa\0\u061c\0\u0198"+ + "\0\u063e\0\u0660\0\u0198\0\u0682\0\u0198\0\u06a4\0\u0198\0\u0198"+ + "\0\u0198\0\u0198\0\u06c6\0\u06e8\0\u070a\0\u0198\0\u072c\0\u074e"+ + "\0\u0770\0\u0792\0\u07b4\0\u05fa\0\u0198\0\u07d6\0\u03da\0\u07f8"+ + "\0\u081a\0\u0198\0\u083c\0\u0198\0\u0198\0\u085e\0\u0880\0\u08a2"+ + "\0\u08c4\0\u0198\0\u08e6\0\u0198\0\u0198\0\u0198\0\u0198\0\u0908"+ + "\0\u0198\0\u0198\0\u0198"; private static int [] zzUnpackRowMap() { - int [] result = new int[96]; + int [] result = new int[107]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -138,59 +145,62 @@ private static int zzUnpackRowMap(String packed, int offset, int [] result) { private static final int [] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\3\1\1\10\36\1\1\11\2\12\1\13\1\14\1\15"+ - "\1\16\1\17\2\14\1\20\3\14\1\21\1\22\1\23"+ - "\1\24\1\12\1\25\1\26\1\27\1\30\2\11\1\31"+ - "\2\11\1\32\1\11\1\33\1\14\1\34\2\14\2\35"+ - "\1\36\1\37\36\14\2\35\37\14\21\40\1\41\20\40"+ - "\16\6\1\42\23\6\1\14\2\35\13\14\1\43\2\14"+ - "\1\44\20\14\3\1\1\45\36\1\1\46\2\47\3\0"+ - "\2\47\2\0\1\47\3\0\1\46\4\47\3\0\11\46"+ - "\4\0\2\12\17\0\1\12\22\0\1\50\121\0\1\51"+ - "\20\0\1\46\2\47\3\0\2\47\2\0\1\47\3\0"+ - "\1\46\4\47\3\0\10\46\1\52\4\0\2\53\4\0"+ - "\1\53\10\0\1\54\2\53\26\0\1\55\11\0\1\56"+ - "\20\0\4\57\1\60\16\57\1\61\16\57\4\62\1\63"+ - "\17\62\1\61\15\62\1\46\2\47\3\0\2\47\2\0"+ - "\1\47\3\0\1\46\4\47\3\0\1\46\1\64\7\46"+ - "\3\0\1\46\2\47\3\0\2\47\2\0\1\47\3\0"+ - "\1\46\4\47\3\0\4\46\1\65\4\46\3\0\1\46"+ - "\2\47\3\0\2\47\2\0\1\47\3\0\1\46\4\47"+ - "\3\0\7\46\1\66\1\46\3\0\1\46\2\67\3\0"+ - "\1\67\1\47\2\0\1\47\3\0\1\46\1\47\1\70"+ - "\2\67\3\0\10\46\1\52\3\0\41\71\1\54\1\0"+ - "\2\35\42\0\1\72\36\0\21\40\1\73\41\40\1\74"+ - "\20\40\16\6\1\75\23\6\16\0\1\76\44\0\1\77"+ - "\23\0\1\100\41\0\1\101\3\0\1\102\1\103\1\104"+ - "\1\105\1\106\1\107\1\110\45\0\1\111\41\0\1\112"+ - "\41\0\1\113\20\0\2\57\1\0\37\57\2\62\1\0"+ - "\37\62\1\46\2\47\3\0\2\47\2\0\1\47\3\0"+ - "\1\46\4\47\3\0\2\46\1\114\6\46\3\0\1\46"+ - "\2\47\3\0\2\47\2\0\1\47\3\0\1\46\4\47"+ - "\3\0\5\46\1\115\3\46\3\0\1\46\2\47\3\0"+ - "\2\47\2\0\1\47\3\0\1\46\4\47\3\0\1\46"+ - "\1\116\7\46\41\0\1\117\3\0\3\72\1\120\36\72"+ - "\21\40\1\121\20\40\21\0\1\122\20\0\16\6\1\75"+ - "\2\6\1\123\20\6\21\0\1\124\23\0\1\101\4\0"+ - "\1\103\1\104\1\105\1\106\1\107\43\0\1\125\23\0"+ - "\1\46\2\47\3\0\2\47\2\0\1\47\3\0\1\46"+ - "\4\47\3\0\1\126\10\46\3\0\1\46\2\47\3\0"+ - "\2\47\2\0\1\47\3\0\1\46\4\47\3\0\1\127"+ - "\10\46\3\0\1\46\2\47\3\0\2\47\2\0\1\47"+ - "\3\0\1\46\4\47\3\0\2\46\1\130\6\46\4\0"+ - "\2\67\3\0\1\67\12\0\2\67\13\0\1\117\3\0"+ - "\3\72\1\131\36\72\16\6\1\42\2\6\1\132\20\6"+ - "\16\0\1\133\23\0\1\46\2\134\3\0\1\134\1\47"+ - "\2\0\1\47\3\0\1\46\2\47\2\134\3\0\11\46"+ - "\3\0\1\46\2\135\3\0\1\135\1\47\2\0\1\47"+ - "\3\0\1\46\2\47\2\135\3\0\11\46\3\0\1\46"+ - "\2\47\3\0\2\47\2\0\1\47\3\0\1\46\4\47"+ - "\3\0\1\136\10\46\6\0\1\137\36\0\1\46\2\140"+ - "\3\0\1\140\1\47\2\0\1\47\3\0\1\46\2\47"+ - "\2\140\3\0\11\46\3\0"; + "\3\1\1\11\36\1\1\12\2\13\1\14\1\15\1\16"+ + "\1\17\1\20\1\21\1\22\5\15\1\23\1\24\1\25"+ + "\1\13\1\26\1\27\1\30\1\31\2\12\1\32\2\12"+ + "\1\33\1\12\1\34\1\15\1\35\2\15\2\36\1\37"+ + "\1\40\36\15\2\36\37\15\10\41\1\42\31\41\17\6"+ + "\1\43\22\6\1\15\2\36\5\15\1\44\6\15\1\45"+ + "\22\15\3\10\1\46\36\10\3\1\1\47\36\1\1\50"+ + "\2\51\2\0\1\51\1\0\3\51\5\0\1\50\3\51"+ + "\3\0\11\50\4\0\2\13\17\0\1\13\22\0\1\52"+ + "\110\0\1\53\1\54\40\0\1\55\31\0\1\50\2\51"+ + "\2\0\1\51\1\0\3\51\5\0\1\50\3\51\3\0"+ + "\10\50\1\56\4\0\2\57\5\0\2\57\7\0\1\60"+ + "\1\57\17\0\4\61\1\62\16\61\1\63\16\61\4\64"+ + "\1\65\17\64\1\63\15\64\1\50\2\51\2\0\1\51"+ + "\1\0\3\51\5\0\1\50\3\51\3\0\1\50\1\66"+ + "\7\50\3\0\1\50\2\51\2\0\1\51\1\0\3\51"+ + "\5\0\1\50\3\51\3\0\4\50\1\67\4\50\3\0"+ + "\1\50\2\51\2\0\1\51\1\0\3\51\5\0\1\50"+ + "\3\51\3\0\7\50\1\70\1\50\3\0\1\50\2\71"+ + "\2\0\1\51\1\0\2\71\1\51\5\0\1\50\1\51"+ + "\1\72\1\71\3\0\10\50\1\56\3\0\41\73\1\60"+ + "\1\0\2\36\42\0\1\74\36\0\10\41\1\75\41\41"+ + "\1\76\31\41\17\6\1\77\22\6\10\0\1\100\50\0"+ + "\1\101\22\0\3\10\1\102\36\10\3\0\1\103\41\0"+ + "\1\104\1\0\1\105\3\0\1\106\1\107\1\110\1\111"+ + "\1\112\1\113\33\0\1\114\41\0\1\115\41\0\1\116"+ + "\31\0\2\61\1\0\37\61\2\64\1\0\37\64\1\50"+ + "\2\51\2\0\1\51\1\0\3\51\5\0\1\50\3\51"+ + "\3\0\2\50\1\117\6\50\3\0\1\50\2\51\2\0"+ + "\1\51\1\0\3\51\5\0\1\50\3\51\3\0\5\50"+ + "\1\120\3\50\3\0\1\50\2\51\2\0\1\51\1\0"+ + "\3\51\5\0\1\50\3\51\3\0\1\50\1\121\7\50"+ + "\41\0\1\122\3\0\3\74\1\123\36\74\10\41\1\124"+ + "\31\41\10\0\1\125\31\0\10\6\1\126\6\6\1\77"+ + "\22\6\10\0\1\127\31\0\3\10\1\130\36\10\3\0"+ + "\1\131\41\0\1\132\1\0\1\105\4\0\1\107\1\110"+ + "\1\111\1\112\43\0\1\133\32\0\1\134\41\0\1\135"+ + "\31\0\1\50\2\51\2\0\1\51\1\0\3\51\5\0"+ + "\1\50\3\51\3\0\1\136\10\50\3\0\1\50\2\51"+ + "\2\0\1\51\1\0\3\51\5\0\1\50\3\51\3\0"+ + "\1\137\10\50\3\0\1\50\2\51\2\0\1\51\1\0"+ + "\3\51\5\0\1\50\3\51\3\0\2\50\1\140\6\50"+ + "\4\0\2\71\4\0\2\71\11\0\1\71\13\0\1\122"+ + "\3\0\3\74\1\141\36\74\10\6\1\142\6\6\1\43"+ + "\22\6\3\10\1\143\36\10\5\0\1\144\53\0\1\145"+ + "\22\0\1\50\2\146\2\0\1\51\1\0\2\146\1\51"+ + "\5\0\1\50\2\51\1\146\3\0\11\50\3\0\1\50"+ + "\2\147\2\0\1\51\1\0\2\147\1\51\5\0\1\50"+ + "\2\51\1\147\3\0\11\50\3\0\1\50\2\51\2\0"+ + "\1\51\1\0\3\51\5\0\1\50\3\51\3\0\1\150"+ + "\10\50\6\0\1\151\36\0\3\10\1\143\1\10\1\152"+ + "\34\10\1\50\2\153\2\0\1\51\1\0\2\153\1\51"+ + "\5\0\1\50\2\51\1\153\3\0\11\50\3\0"; private static int [] zzUnpackTrans() { - int [] result = new int[2040]; + int [] result = new int[2346]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -231,15 +241,16 @@ private static int zzUnpackTrans(String packed, int offset, int [] result) { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\2\1\2\0\2\1\1\0\4\1\3\11\1\1\1\11"+ - "\1\1\1\11\4\1\1\11\7\1\1\11\6\1\1\0"+ - "\1\11\1\1\2\0\2\11\1\0\1\1\2\0\1\11"+ - "\5\0\1\11\1\1\1\0\4\1\1\0\3\11\1\1"+ - "\5\11\1\1\1\11\1\0\1\11\4\0\2\1\1\11"+ - "\1\1\5\0\1\1\4\11\1\0\2\11"; + "\2\1\2\0\2\1\1\0\5\1\4\11\3\1\1\11"+ + "\3\1\1\11\7\1\1\11\7\1\1\0\1\11\2\1"+ + "\3\0\2\11\2\0\1\11\5\0\1\11\1\1\1\0"+ + "\4\1\1\11\1\0\1\1\1\11\1\1\1\11\1\1"+ + "\4\11\2\1\1\0\1\11\4\0\2\1\1\11\1\1"+ + "\1\0\2\1\1\11\1\0\2\11\3\0\1\1\1\11"+ + "\1\1\4\11\1\0\3\11"; private static int [] zzUnpackAttribute() { - int [] result = new int[96]; + int [] result = new int[107]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -515,7 +526,7 @@ public IElementType advance() throws java.io.IOException { while (true) { if (zzCurrentPosL < zzEndReadL) - zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++)); + zzInput = zzBufferL.charAt(zzCurrentPosL++); else if (zzAtEOF) { zzInput = YYEOF; break zzForAction; @@ -535,7 +546,7 @@ else if (zzAtEOF) { break zzForAction; } else { - zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++)); + zzInput = zzBufferL.charAt(zzCurrentPosL++); } } int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; @@ -556,183 +567,199 @@ else if (zzAtEOF) { zzMarkedPos = zzMarkedPosL; switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 20: - { // otherwise, if the remaining text just contains the one escaped mustache, then it's all CONTENT - return HbTokenTypes.CONTENT; - } - case 36: break; - case 12: - { // backtrack over any stache characters at the end of this string - while (yylength() > 0 && yytext().subSequence(yylength() - 1, yylength()).toString().equals("{")) { - yypushback(1); - } - - // inspect the characters leading up to this mustache for escaped characters - if (yylength() > 1 && yytext().subSequence(yylength() - 2, yylength()).toString().equals("\\\\")) { - return HbTokenTypes.CONTENT; // double-slash is just more content - } else if (yylength() > 0 && yytext().toString().substring(yylength() - 1, yylength()).equals("\\")) { - yypushback(1); // put the escape char back - yypushState(emu); - } else { - yypushState(mu); - } - - // we stray from the handlebars.js lexer here since we need our WHITE_SPACE more clearly delineated - // and we need to avoid creating extra tokens for empty strings (makes the parser and formatter happier) - if (!yytext().toString().equals("")) { - if (yytext().toString().trim().length() == 0) { - return HbTokenTypes.WHITE_SPACE; - } else { - return HbTokenTypes.CONTENT; - } - } - } - case 37: break; - case 11: - { return HbTokenTypes.ESCAPE_CHAR; - } - case 38: break; case 2: { return HbTokenTypes.WHITE_SPACE; } - case 39: break; - case 35: - // lookahead expression with fixed base length - zzMarkedPos = zzStartRead + 5; - { return HbTokenTypes.BOOLEAN; - } case 40: break; - case 34: - // lookahead expression with fixed base length - zzMarkedPos = zzStartRead + 4; - { return HbTokenTypes.BOOLEAN; + case 14: + { return HbTokenTypes.OPEN; } case 41: break; case 23: - { return HbTokenTypes.OPEN_PARTIAL; + { return HbTokenTypes.OPEN_ENDBLOCK; } case 42: break; - case 8: - { return HbTokenTypes.SEP; + case 17: + { return HbTokenTypes.ID; } case 43: break; - case 13: - // lookahead expression with fixed lookahead length - yypushback(1); + case 16: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 1; { return HbTokenTypes.ID; } case 44: break; - case 15: - // lookahead expression with fixed base length - zzMarkedPos = zzStartRead + 1; + case 13: + // lookahead expression with fixed lookahead length + yypushback(1); { return HbTokenTypes.ID; } case 45: break; - case 16: - { return HbTokenTypes.ID; + case 33: + { yypushback(4); yybegin(comment_end); return HbTokenTypes.COMMENT_CONTENT; } case 46: break; - case 32: - { yypopState(); yypushState(comment_block); return HbTokenTypes.COMMENT_OPEN; + case 5: + { return HbTokenTypes.INVALID; } case 47: break; - case 33: - // lookahead expression with fixed base length - zzMarkedPos = zzStartRead + 4; - { return HbTokenTypes.ELSE; + case 15: + { yypopState(); return HbTokenTypes.CLOSE; } case 48: break; - case 6: - { return HbTokenTypes.OPEN_SEXPR; + case 22: + { return HbTokenTypes.OPEN_UNESCAPED; } case 49: break; - case 4: - { yypopState(); return HbTokenTypes.UNCLOSED_COMMENT; + case 11: + { return HbTokenTypes.ESCAPE_CHAR; } case 50: break; - case 14: - { return HbTokenTypes.OPEN; + case 3: + { return HbTokenTypes.UNCLOSED_COMMENT; } case 51: break; - case 30: - { // grab everything up to the next open stache - // backtrack over any stache characters or escape characters at the end of this string - while (yylength() > 0 - && (yytext().subSequence(yylength() - 1, yylength()).toString().equals("{") - || yytext().subSequence(yylength() - 1, yylength()).toString().equals("\\"))) { - yypushback(1); - } - - yypopState(); - return HbTokenTypes.CONTENT; + case 25: + { return HbTokenTypes.OPEN_BLOCK; } case 52: break; - case 25: - { return HbTokenTypes.OPEN_ENDBLOCK; + case 19: + // lookahead expression with fixed lookahead length + yypushback(1); + { return HbTokenTypes.NUMBER; } case 53: break; - case 26: - { return HbTokenTypes.OPEN_INVERSE; + case 30: + { return HbTokenTypes.OPEN_RAW_BLOCK; } case 54: break; - case 18: - { return HbTokenTypes.STRING; + case 36: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 4; + { return HbTokenTypes.ELSE; } case 55: break; - case 24: - { return HbTokenTypes.OPEN_BLOCK; + case 8: + { return HbTokenTypes.CLOSE_SEXPR; } case 56: break; - case 19: - // lookahead expression with fixed lookahead length - yypushback(1); - { return HbTokenTypes.NUMBER; + case 4: + { yypopState(); return HbTokenTypes.UNCLOSED_COMMENT; } case 57: break; - case 3: - { return HbTokenTypes.UNCLOSED_COMMENT; + case 31: + { yypopState(); yypushState(raw); return HbTokenTypes.CLOSE_RAW_BLOCK; } case 58: break; - case 10: - { return HbTokenTypes.DATA_PREFIX; + case 9: + { return HbTokenTypes.EQUALS; } case 59: break; - case 22: - { return HbTokenTypes.OPEN_UNESCAPED; + case 10: + { return HbTokenTypes.DATA_PREFIX; } case 60: break; - case 1: - { return HbTokenTypes.CONTENT; + case 26: + { return HbTokenTypes.OPEN_INVERSE; } case 61: break; - case 9: - { return HbTokenTypes.EQUALS; + case 20: + { // otherwise, if the remaining text just contains the one escaped mustache, then it's all CONTENT + return HbTokenTypes.CONTENT; } case 62: break; - case 27: - { yypopState(); yypushState(comment); return HbTokenTypes.COMMENT_OPEN; + case 34: + { return HbTokenTypes.END_RAW_BLOCK; } case 63: break; - case 28: - { yypopState(); return HbTokenTypes.CLOSE_UNESCAPED; + case 1: + { return HbTokenTypes.CONTENT; } case 64: break; - case 17: - { yypopState(); return HbTokenTypes.CLOSE; + case 28: + { yypopState(); return HbTokenTypes.CLOSE_UNESCAPED; } case 65: break; - case 7: - { return HbTokenTypes.CLOSE_SEXPR; + case 35: + { yypopState(); yypushState(comment_block); return HbTokenTypes.COMMENT_OPEN; } case 66: break; - case 21: - { yypopState(); return HbTokenTypes.COMMENT_CLOSE; + case 27: + { yypopState(); yypushState(comment); return HbTokenTypes.COMMENT_OPEN; } case 67: break; - case 31: - { yypushback(4); yybegin(comment_end); return HbTokenTypes.COMMENT_CONTENT; + case 21: + { yypopState(); return HbTokenTypes.COMMENT_CLOSE; } case 68: break; + case 39: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 5; + { return HbTokenTypes.BOOLEAN; + } + case 69: break; + case 37: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 4; + { return HbTokenTypes.BOOLEAN; + } + case 70: break; + case 38: + { // backtrack over the END_RAW_BLOCK we picked up at the end of this string + yypushback(5); + + yypopState(); + + // we stray from the handlebars.js lexer here since we need our WHITE_SPACE more clearly delineated + // and we need to avoid creating extra tokens for empty strings (makes the parser and formatter happier) + if (!yytext().toString().equals("")) { + if (yytext().toString().trim().length() == 0) { + return HbTokenTypes.WHITE_SPACE; + } else { + return HbTokenTypes.CONTENT; + } + } + } + case 71: break; + case 7: + { return HbTokenTypes.OPEN_SEXPR; + } + case 72: break; + case 6: + { return HbTokenTypes.SEP; + } + case 73: break; + case 12: + { // backtrack over any stache characters at the end of this string + while (yylength() > 0 && yytext().subSequence(yylength() - 1, yylength()).toString().equals("{")) { + yypushback(1); + } + + // inspect the characters leading up to this mustache for escaped characters + if (yylength() > 1 && yytext().subSequence(yylength() - 2, yylength()).toString().equals("\\\\")) { + return HbTokenTypes.CONTENT; // double-slash is just more content + } else if (yylength() > 0 && yytext().toString().substring(yylength() - 1, yylength()).equals("\\")) { + yypushback(1); // put the escape char back + yypushState(emu); + } else { + yypushState(mu); + } + + // we stray from the handlebars.js lexer here since we need our WHITE_SPACE more clearly delineated + // and we need to avoid creating extra tokens for empty strings (makes the parser and formatter happier) + if (!yytext().toString().equals("")) { + if (yytext().toString().trim().length() == 0) { + return HbTokenTypes.WHITE_SPACE; + } else { + return HbTokenTypes.CONTENT; + } + } + } + case 74: break; + case 18: + { return HbTokenTypes.STRING; + } + case 75: break; case 29: { // backtrack over any extra stache characters at the end of this string while (yylength() > 2 && yytext().subSequence(yylength() - 3, yylength()).toString().equals("}}}")) { @@ -743,11 +770,24 @@ else if (zzAtEOF) { yybegin(comment_end); return HbTokenTypes.COMMENT_CONTENT; } - case 69: break; - case 5: - { return HbTokenTypes.INVALID; + case 76: break; + case 32: + { // grab everything up to the next open stache + // backtrack over any stache characters or escape characters at the end of this string + while (yylength() > 0 + && (yytext().subSequence(yylength() - 1, yylength()).toString().equals("{") + || yytext().subSequence(yylength() - 1, yylength()).toString().equals("\\"))) { + yypushback(1); } - case 70: break; + + yypopState(); + return HbTokenTypes.CONTENT; + } + case 77: break; + case 24: + { return HbTokenTypes.OPEN_PARTIAL; + } + case 78: break; default: if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; diff --git a/handlebars/src/com/dmarcotte/handlebars/parsing/HbParsing.java b/handlebars/src/com/dmarcotte/handlebars/parsing/HbParsing.java index b5077c055b3..9c04f3dfca3 100644 --- a/handlebars/src/com/dmarcotte/handlebars/parsing/HbParsing.java +++ b/handlebars/src/com/dmarcotte/handlebars/parsing/HbParsing.java @@ -113,7 +113,8 @@ private void parseStatements(PsiBuilder builder) { /** * statement - * : openInverse program closeBlock + * : openRawBlock CONTENT endRawBlock + * | openInverse program closeBlock * | openBlock program closeBlock * | mustache * | partial @@ -126,6 +127,18 @@ private void parseStatements(PsiBuilder builder) { private boolean parseStatement(PsiBuilder builder) { IElementType tokenType = builder.getTokenType(); + if (tokenType == OPEN_RAW_BLOCK) { + PsiBuilder.Marker blockMarker = builder.mark(); + if (parseOpenRawBlock(builder)) { + parseRestOfBlock(builder, blockMarker, true); + } + else { + return false; + } + + return true; + } + if (atOpenInverseExpression(builder)) { PsiBuilder.Marker inverseBlockStartMarker = builder.mark(); PsiBuilder.Marker lookAheadMarker = builder.mark(); @@ -144,7 +157,7 @@ private boolean parseStatement(PsiBuilder builder) { PsiBuilder.Marker blockMarker = builder.mark(); if (parseOpenInverse(builder)) { - parseRestOfBlock(builder, blockMarker); + parseRestOfBlock(builder, blockMarker, false); } else { return false; @@ -156,7 +169,7 @@ private boolean parseStatement(PsiBuilder builder) { if (tokenType == OPEN_BLOCK) { PsiBuilder.Marker blockMarker = builder.mark(); if (parseOpenBlock(builder)) { - parseRestOfBlock(builder, blockMarker); + parseRestOfBlock(builder, blockMarker, false); } else { return false; @@ -206,12 +219,35 @@ private boolean parseStatement(PsiBuilder builder) { *

* NOTE: will resolve the given blockMarker */ - private void parseRestOfBlock(PsiBuilder builder, PsiBuilder.Marker blockMarker) { + private void parseRestOfBlock(PsiBuilder builder, PsiBuilder.Marker blockMarker, boolean raw) { parseProgram(builder); - parseCloseBlock(builder); + if (raw) { + parseCloseRawBlock(builder); + } else { + parseCloseBlock(builder); + } blockMarker.done(HbTokenTypes.BLOCK_WRAPPER); } + /** + * openRawBlock + * : OPEN_RAW_BLOCK sexpr CLOSE_RAW_BLOCK + */ + private boolean parseOpenRawBlock(PsiBuilder builder) { + PsiBuilder.Marker openRawBlockStacheMarker = builder.mark(); + if (!parseLeafToken(builder, OPEN_RAW_BLOCK)) { + openRawBlockStacheMarker.drop(); + return false; + } + + if (parseSexpr(builder)) { + parseLeafTokenGreedy(builder, CLOSE_RAW_BLOCK); + } + + openRawBlockStacheMarker.done(OPEN_BLOCK_STACHE); + return true; + } + /** * openBlock * : OPEN_BLOCK sexpr CLOSE { $$ = new yy.MustacheNode($2[0], $2[1]); } @@ -263,6 +299,27 @@ private boolean parseOpenInverse(PsiBuilder builder) { return true; } + /** + * closeRawBlock + * : END_RAW_BLOCK path CLOSE_RAW_BLOCK + * ; + */ + private boolean parseCloseRawBlock(PsiBuilder builder) { + PsiBuilder.Marker closeRawBlockMarker = builder.mark(); + + if (!parseLeafToken(builder, END_RAW_BLOCK)) { + closeRawBlockMarker.drop(); + return false; + } + + PsiBuilder.Marker mustacheNameMark = builder.mark(); + parsePath(builder); + mustacheNameMark.done(HbTokenTypes.MUSTACHE_NAME); + parseLeafTokenGreedy(builder, CLOSE_RAW_BLOCK); + closeRawBlockMarker.done(CLOSE_BLOCK_STACHE); + return true; + } + /** * closeBlock * : OPEN_ENDBLOCK path CLOSE { $$ = $2; } diff --git a/handlebars/src/com/dmarcotte/handlebars/parsing/HbTokenTypes.java b/handlebars/src/com/dmarcotte/handlebars/parsing/HbTokenTypes.java index 156861eec19..e6f10a418ca 100644 --- a/handlebars/src/com/dmarcotte/handlebars/parsing/HbTokenTypes.java +++ b/handlebars/src/com/dmarcotte/handlebars/parsing/HbTokenTypes.java @@ -45,6 +45,9 @@ private HbTokenTypes() { public static final IElementType OPEN_UNESCAPED = new HbElementType("OPEN_UNESCAPED", "hb.parsing.element.expected.open_unescaped"); public static final IElementType OPEN_SEXPR = new HbElementType("OPEN_SEXPR", "hb.parsing.element.expected.open_sexpr"); public static final IElementType CLOSE_SEXPR = new HbElementType("CLOSE_SEXPR", "hb.parsing.element.expected.close_sexpr"); + public static final IElementType OPEN_RAW_BLOCK = new HbElementType("OPEN_RAW_BLOCK", "hb.parsing.element.expected.open_raw_block"); + public static final IElementType END_RAW_BLOCK = new HbElementType("END_RAW_BLOCK", "hb.parsing.element.expected.end_raw_block"); + public static final IElementType CLOSE_RAW_BLOCK = new HbElementType("CLOSE_RAW_BLOCK", "hb.parsing.element.expected.close_raw_block"); public static final IElementType EQUALS = new HbElementType("EQUALS", "hb.parsing.element.expected.equals"); public static final IElementType ID = new HbElementType("ID", "hb.parsing.element.expected.id"); public static final IElementType DATA_PREFIX = new HbElementType("DATA_PREFIX", "hb.parsing.element.expected.data"); diff --git a/handlebars/src/com/dmarcotte/handlebars/parsing/handlebars.flex b/handlebars/src/com/dmarcotte/handlebars/parsing/handlebars.flex index 6585e7d3d88..2a7752a5329 100644 --- a/handlebars/src/com/dmarcotte/handlebars/parsing/handlebars.flex +++ b/handlebars/src/com/dmarcotte/handlebars/parsing/handlebars.flex @@ -1,7 +1,7 @@ // We base our lexer directly on the official handlebars.l lexer definition, // making some modifications to account for Jison/JFlex syntax and functionality differences // -// Revision ported: https://github.com/wycats/handlebars.js/commit/58a0b4f17d5338793c92cf4d104e9c44cc485c5b#src/handlebars.l +// Revision ported: https://github.com/wycats/handlebars.js/blob/14b7ef9066d107dc83deedc8e6791947811cc764/src/handlebars.l package com.dmarcotte.handlebars.parsing; @@ -46,6 +46,7 @@ WhiteSpace = {LineTerminator} | [ \t\f] %state comment_block %state comment_end %state data +%state raw %% @@ -105,10 +106,36 @@ WhiteSpace = {LineTerminator} | [ \t\f] } } + { + ~"{{{{/" { + // backtrack over the END_RAW_BLOCK we picked up at the end of this string + yypushback(5); + + yypopState(); + + // we stray from the handlebars.js lexer here since we need our WHITE_SPACE more clearly delineated + // and we need to avoid creating extra tokens for empty strings (makes the parser and formatter happier) + if (!yytext().toString().equals("")) { + if (yytext().toString().trim().length() == 0) { + return HbTokenTypes.WHITE_SPACE; + } else { + return HbTokenTypes.CONTENT; + } + } + } + + // Check for anything that is not a string containing "{{{{/"; that's CONTENT + !([^]*"{{{{/"[^]*) { return HbTokenTypes.CONTENT; } +} + { "(" { return HbTokenTypes.OPEN_SEXPR; } ")" { return HbTokenTypes.CLOSE_SEXPR; } + "{{{{" { return HbTokenTypes.OPEN_RAW_BLOCK; } + "{{{{/" { return HbTokenTypes.END_RAW_BLOCK; } + "}}}}" { yypopState(); yypushState(raw); return HbTokenTypes.CLOSE_RAW_BLOCK; } + "{{"\~?">" { return HbTokenTypes.OPEN_PARTIAL; } "{{"\~?"#" { return HbTokenTypes.OPEN_BLOCK; } "{{"\~?"/" { return HbTokenTypes.OPEN_ENDBLOCK; } diff --git a/handlebars/test/data/inspections/afterWrongOpenRawBlock.hbs b/handlebars/test/data/inspections/afterWrongOpenRawBlock.hbs new file mode 100644 index 00000000000..1db2150a3b4 --- /dev/null +++ b/handlebars/test/data/inspections/afterWrongOpenRawBlock.hbs @@ -0,0 +1,4 @@ + +{{{{foo}}}} + +{{{{/foo}}}} \ No newline at end of file diff --git a/handlebars/test/data/inspections/beforeWrongOpenRawBlock.hbs b/handlebars/test/data/inspections/beforeWrongOpenRawBlock.hbs new file mode 100644 index 00000000000..723dc9fc706 --- /dev/null +++ b/handlebars/test/data/inspections/beforeWrongOpenRawBlock.hbs @@ -0,0 +1,4 @@ + +{{{{bar}}}} + +{{{{/foo}}}} \ No newline at end of file diff --git a/handlebars/test/data/parser/RawBlock.hbs b/handlebars/test/data/parser/RawBlock.hbs new file mode 100644 index 00000000000..79db02f270a --- /dev/null +++ b/handlebars/test/data/parser/RawBlock.hbs @@ -0,0 +1 @@ +{{{{raw}}}} {{test}} {{{{/raw}}}} \ No newline at end of file diff --git a/handlebars/test/data/parser/RawBlock.txt b/handlebars/test/data/parser/RawBlock.txt new file mode 100644 index 00000000000..382c8dbb2f2 --- /dev/null +++ b/handlebars/test/data/parser/RawBlock.txt @@ -0,0 +1,23 @@ +HbFile:RawBlock.hbs + HbStatementsImpl(STATEMENTS) + HbBlockWrapperImpl(BLOCK_WRAPPER) + HbOpenBlockMustacheImpl(OPEN_BLOCK_STACHE) + HbPsiElementImpl([Hb] OPEN_RAW_BLOCK) + PsiElement([Hb] OPEN_RAW_BLOCK)('{{{{') + HbMustacheNameImpl(MUSTACHE_NAME) + HbPathImpl(PATH) + HbPsiElementImpl([Hb] ID) + PsiElement([Hb] ID)('raw') + HbPsiElementImpl([Hb] CLOSE_RAW_BLOCK) + PsiElement([Hb] CLOSE_RAW_BLOCK)('}}}}') + HbStatementsImpl(STATEMENTS) + PsiElement([Hb] CONTENT)(' {{test}} ') + HbCloseBlockMustacheImpl(CLOSE_BLOCK_STACHE) + HbPsiElementImpl([Hb] END_RAW_BLOCK) + PsiElement([Hb] END_RAW_BLOCK)('{{{{/') + HbMustacheNameImpl(MUSTACHE_NAME) + HbPathImpl(PATH) + HbPsiElementImpl([Hb] ID) + PsiElement([Hb] ID)('raw') + HbPsiElementImpl([Hb] CLOSE_RAW_BLOCK) + PsiElement([Hb] CLOSE_RAW_BLOCK)('}}}}') \ No newline at end of file diff --git a/handlebars/test/data/parser/RawBlockParameters.hbs b/handlebars/test/data/parser/RawBlockParameters.hbs new file mode 100644 index 00000000000..9ca0376dae5 --- /dev/null +++ b/handlebars/test/data/parser/RawBlockParameters.hbs @@ -0,0 +1 @@ +{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}} \ No newline at end of file diff --git a/handlebars/test/data/parser/RawBlockParameters.txt b/handlebars/test/data/parser/RawBlockParameters.txt new file mode 100644 index 00000000000..2b3737b1a47 --- /dev/null +++ b/handlebars/test/data/parser/RawBlockParameters.txt @@ -0,0 +1,35 @@ +HbFile:RawBlockParameters.hbs + HbStatementsImpl(STATEMENTS) + HbBlockWrapperImpl(BLOCK_WRAPPER) + HbOpenBlockMustacheImpl(OPEN_BLOCK_STACHE) + HbPsiElementImpl([Hb] OPEN_RAW_BLOCK) + PsiElement([Hb] OPEN_RAW_BLOCK)('{{{{') + HbMustacheNameImpl(MUSTACHE_NAME) + HbPathImpl(PATH) + HbPsiElementImpl([Hb] ID) + PsiElement([Hb] ID)('raw') + PsiWhiteSpace(' ') + HbParamImpl(PARAM) + HbPsiElementImpl([Hb] NUMBER) + PsiElement([Hb] NUMBER)('1') + PsiWhiteSpace(' ') + HbParamImpl(PARAM) + HbPsiElementImpl([Hb] NUMBER) + PsiElement([Hb] NUMBER)('2') + PsiWhiteSpace(' ') + HbParamImpl(PARAM) + HbPsiElementImpl([Hb] NUMBER) + PsiElement([Hb] NUMBER)('3') + HbPsiElementImpl([Hb] CLOSE_RAW_BLOCK) + PsiElement([Hb] CLOSE_RAW_BLOCK)('}}}}') + HbStatementsImpl(STATEMENTS) + PsiElement([Hb] CONTENT)(' {{test}} ') + HbCloseBlockMustacheImpl(CLOSE_BLOCK_STACHE) + HbPsiElementImpl([Hb] END_RAW_BLOCK) + PsiElement([Hb] END_RAW_BLOCK)('{{{{/') + HbMustacheNameImpl(MUSTACHE_NAME) + HbPathImpl(PATH) + HbPsiElementImpl([Hb] ID) + PsiElement([Hb] ID)('raw') + HbPsiElementImpl([Hb] CLOSE_RAW_BLOCK) + PsiElement([Hb] CLOSE_RAW_BLOCK)('}}}}') \ No newline at end of file diff --git a/handlebars/test/src/com/dmarcotte/handlebars/inspections/HbBlockMismatchFixTest.java b/handlebars/test/src/com/dmarcotte/handlebars/inspections/HbBlockMismatchFixTest.java index 8b40f5bad4b..4ac870b173a 100644 --- a/handlebars/test/src/com/dmarcotte/handlebars/inspections/HbBlockMismatchFixTest.java +++ b/handlebars/test/src/com/dmarcotte/handlebars/inspections/HbBlockMismatchFixTest.java @@ -33,6 +33,10 @@ public void testWrongOpenBlock2() { doTest("Change block start"); } + public void testWrongOpenRawBlock() { + doTest("Change block start"); + } + private void doTest(String intentionHint) { myFixture.configureByFile("inspections/before" + getTestName(false) + ".hbs"); final IntentionAction intention = myFixture.findSingleIntention(intentionHint); diff --git a/handlebars/test/src/com/dmarcotte/handlebars/parsing/HbLexerFreeFormTest.java b/handlebars/test/src/com/dmarcotte/handlebars/parsing/HbLexerFreeFormTest.java index b055169d18c..67b3b34ea26 100644 --- a/handlebars/test/src/com/dmarcotte/handlebars/parsing/HbLexerFreeFormTest.java +++ b/handlebars/test/src/com/dmarcotte/handlebars/parsing/HbLexerFreeFormTest.java @@ -98,9 +98,9 @@ public void testRegularMustacheFollowedByUnescaped() { } public void testTooManyMustaches() { - TokenizerResult result = tokenize("{{{{"); - result.shouldMatchTokenTypes(OPEN_UNESCAPED, INVALID); - result.shouldMatchTokenContent("{{{", "{"); + TokenizerResult result = tokenize("{{{{{"); + result.shouldMatchTokenTypes(OPEN_RAW_BLOCK, INVALID); + result.shouldMatchTokenContent("{{{{", "{"); } public void testTooManyCommentCloseStaches() { @@ -276,4 +276,10 @@ public void testDataParamsForPartials() { result.shouldMatchTokenTypes(OPEN_PARTIAL, ID, WHITE_SPACE, DATA_PREFIX, ID, SEP, ID, CLOSE); result.shouldMatchTokenContent("{{>", "foo", " ", "@", "bar", ".", "baz", "}}"); } + + public void testRawBlock() { + TokenizerResult result = tokenize("{{{{raw}}}} {{test}} {{{{/raw}}}}"); + result.shouldMatchTokenTypes(OPEN_RAW_BLOCK, ID, CLOSE_RAW_BLOCK, CONTENT, END_RAW_BLOCK, ID, CLOSE_RAW_BLOCK); + result.shouldMatchTokenContent("{{{{", "raw", "}}}}", " {{test}} ", "{{{{/", "raw", "}}}}"); + } } diff --git a/handlebars/test/src/com/dmarcotte/handlebars/parsing/HbParserFreeFormTest.java b/handlebars/test/src/com/dmarcotte/handlebars/parsing/HbParserFreeFormTest.java index 98a8216d3c2..5f2efbfa0ce 100644 --- a/handlebars/test/src/com/dmarcotte/handlebars/parsing/HbParserFreeFormTest.java +++ b/handlebars/test/src/com/dmarcotte/handlebars/parsing/HbParserFreeFormTest.java @@ -83,4 +83,12 @@ public void testParamWithDecimal() { public void testSubexpressions() { doTest(true); } + + public void testRawBlock() { + doTest(true); + } + + public void testRawBlockParameters() { + doTest(true); + } }