Skip to content

Commit

Permalink
Support for raw block helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
dmarcotte committed Mar 30, 2015
1 parent ab1611c commit 42f712e
Show file tree
Hide file tree
Showing 13 changed files with 437 additions and 224 deletions.
470 changes: 255 additions & 215 deletions handlebars/gen/com/dmarcotte/handlebars/parsing/_HbLexer.java

Large diffs are not rendered by default.

67 changes: 62 additions & 5 deletions handlebars/src/com/dmarcotte/handlebars/parsing/HbParsing.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ private void parseStatements(PsiBuilder builder) {

/**
* statement
* : openInverse program closeBlock
* : openRawBlock CONTENT endRawBlock
* | openInverse program closeBlock
* | openBlock program closeBlock
* | mustache
* | partial
Expand All @@ -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();
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -206,12 +219,35 @@ private boolean parseStatement(PsiBuilder builder) {
* <p/>
* 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]); }
Expand Down Expand Up @@ -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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
29 changes: 28 additions & 1 deletion handlebars/src/com/dmarcotte/handlebars/parsing/handlebars.flex
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -46,6 +46,7 @@ WhiteSpace = {LineTerminator} | [ \t\f]
%state comment_block
%state comment_end
%state data
%state raw

%%

Expand Down Expand Up @@ -105,10 +106,36 @@ WhiteSpace = {LineTerminator} | [ \t\f]
}
}

<raw> {
~"{{{{/" {
// 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; }
}

<mu> {
"(" { 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; }
Expand Down
4 changes: 4 additions & 0 deletions handlebars/test/data/inspections/afterWrongOpenRawBlock.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!-- "Change block start 'bar' to 'foo'" "true" -->
{{{{foo}}}}

{{{{/foo}}}}
4 changes: 4 additions & 0 deletions handlebars/test/data/inspections/beforeWrongOpenRawBlock.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!-- "Change block start 'bar' to 'foo'" "true" -->
{{{{<caret>bar}}}}

{{{{/foo}}}}
1 change: 1 addition & 0 deletions handlebars/test/data/parser/RawBlock.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{{{raw}}}} {{test}} {{{{/raw}}}}
23 changes: 23 additions & 0 deletions handlebars/test/data/parser/RawBlock.txt
Original file line number Diff line number Diff line change
@@ -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)('}}}}')
1 change: 1 addition & 0 deletions handlebars/test/data/parser/RawBlockParameters.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}
35 changes: 35 additions & 0 deletions handlebars/test/data/parser/RawBlockParameters.txt
Original file line number Diff line number Diff line change
@@ -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)('}}}}')
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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", "}}}}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,12 @@ public void testParamWithDecimal() {
public void testSubexpressions() {
doTest(true);
}

public void testRawBlock() {
doTest(true);
}

public void testRawBlockParameters() {
doTest(true);
}
}

0 comments on commit 42f712e

Please sign in to comment.