Skip to content

Commit

Permalink
Switch Expressions (#186)
Browse files Browse the repository at this point in the history
* Switch Expressions for Java 17+

Co-authored-by: Asaf Ben Natan <[email protected]>
  • Loading branch information
asafbennatan and asaf-wizzdi authored Nov 9, 2024
1 parent 2caadbf commit 5246989
Show file tree
Hide file tree
Showing 22 changed files with 799 additions and 2 deletions.
32 changes: 32 additions & 0 deletions docs/SYNTAX.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,38 @@ both ```i am in the "a" block``` and ```i am in the "b" block"``` would be outpu
}
}

### Enhanced Switch - case - default blocks (@switch) JDK17+

Enhanced Java switch - case - default control flow. The left curly character ```{``` indicates
the start of a block and the right curly character ```}``` marks the end.

Switch block with case and default example.

@switch (s) {
case ("a") -> {
i am in the "a" block
}
case ("b") -> {
i am in the "b" block
}
default -> {
i am in the "default" block
}
}

Without a default block.

@switch (v) {
case (1) -> {
i am in the "a" block
}
case (2) -> {
i am in the "b" block
}
}

The Difference from normal Switch block is that @break is not required and each case is separate from the other.

### With blocks (set one or more variables) (@with)

As of v0.12.0 a `@with` block sets a variable to a value within a scoped block. Once the block
Expand Down
22 changes: 22 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -174,5 +174,27 @@

</dependencies>
</dependencyManagement>
<!-- things to do if running on JDK 17 -->
<profiles>
<profile>
<id>java17-settings</id>
<activation>
<jdk>[17,)</jdk>
</activation>
<properties>
<javadoc.opts>-Xdoclint:none</javadoc.opts>
</properties>
<modules>
<module>rocker-runtime</module>
<module>rocker-compiler</module>
<module>rocker-maven-plugin</module>
<module>rocker-gradle-plugin</module>
<module>rocker-test-template</module>
<module>rocker-test-template17</module>
<module>rocker-test-reload</module>
<module>rocker-bom</module>
</modules>
</profile>
</profiles>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,19 @@ CASE
: Ws? 'case' Ws? Parentheses Ws? '{'
;

//switch block should not allow WS as this will generate statments within switch block which are not case or default
CASE_EXPRESSION
: Ws? 'case' Ws? Parentheses Ws? '->' Ws? '{'
;

//switch block should not allow WS as this will generate statments within switch block which are not case or default
DEFAULT
: Ws? 'default' Ws? '{' Ws?;

//switch block should not allow WS as this will generate statments within switch block which are not case or default
DEFAULT_EXPRESSION
: Ws? 'default' Ws? '->' Ws? '{' Ws?;


LCURLY
: '{'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ templateContent
;

block
: (ifBlock | forBlock | withBlock|switchBlock)
: (ifBlock | forBlock | withBlock | switchBlock | switchExpressionBlock)
;

ifBlock
Expand Down Expand Up @@ -127,7 +127,7 @@ evalExpression
;

switchBlock
: AT MV_SWITCH (switchCase|switchDefault|plain|comment)* RCURLY
: AT MV_SWITCH ( switchCase | switchDefault | plain | comment)* RCURLY
;

switchCase
Expand All @@ -138,4 +138,15 @@ switchDefault
: DEFAULT templateContent* RCURLY
;

switchExpressionBlock
: AT MV_SWITCH ( switchExpressionCase | switchExpressionDefault | plain | comment)* RCURLY
;

switchExpressionCase
: CASE_EXPRESSION templateContent* RCURLY
;

switchExpressionDefault
: DEFAULT_EXPRESSION templateContent* RCURLY
;

Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,63 @@ else if (unit instanceof SwitchDefaultBlockEnd) {
.append(blockEnd.pop())
.append(" // default end ").append(sourceRef(unit)).append(CRLF);
}

else if(unit instanceof SwitchExpressionBlock){

SwitchExpressionBlock block = (SwitchExpressionBlock) unit;

tab(w, depth+indent)
.append("switch ")
.append(block.getExpression())
.append(" {").append(CRLF);

blockEnd.push("}");

depth++;
} else if (unit instanceof SwitchExpressionBlockEnd) {
depth--;

tab(w, depth+indent)
.append(blockEnd.pop())
.append(" // switch end ").append(sourceRef(unit)).append(CRLF);


} else if (unit instanceof SwitchCaseExpressionBlock) {

SwitchCaseExpressionBlock block = (SwitchCaseExpressionBlock) unit;

tab(w, depth+indent)
.append("case ")
.append(block.getExpression())
.append(" -> ")
.append(" {").append(CRLF);

blockEnd.push("}");

depth++;
} else if (unit instanceof SwitchCaseExpressionBlockEnd) {
depth--;

tab(w, depth+indent)
.append(blockEnd.pop())
.append(" // case end ").append(sourceRef(unit)).append(CRLF);
}else if (unit instanceof SwitchDefaultExpressionBlock) {

tab(w, depth+indent)
.append("default ")
.append("-> ")
.append(" {").append(CRLF);

blockEnd.push("}");
depth++;
}
else if (unit instanceof SwitchDefaultExpressionBlockEnd) {
depth--;

tab(w, depth+indent)
.append(blockEnd.pop())
.append(" // default end ").append(sourceRef(unit)).append(CRLF);
}
//log.info(" src (@ {}): [{}]", unit.getSourceRef(), unit.getSourceRef().getConsoleFriendlyText());
}

Expand Down Expand Up @@ -1149,5 +1206,7 @@ private TemplateModel postProcess(TemplateModel templateModel) throws PostProces

return templateModel;
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,55 @@ public void exitSwitchBlock(RockerParser.SwitchBlockContext ctx) {
verifySwitchBlock();
}

@Override
public void enterSwitchExpressionBlock(RockerParser.SwitchExpressionBlockContext ctx) {

SourceRef sourceRef = createSourceRef(ctx);
final String text = ctx.MV_SWITCH().getText();
final int idxFirst = text.indexOf('(');
final int idxLast = text.lastIndexOf(')');
final String expression = text.substring(idxFirst, idxLast + 1);
model.getUnits().add(new SwitchExpressionBlock(sourceRef, expression));
}

@Override
public void exitSwitchExpressionBlock(RockerParser.SwitchExpressionBlockContext ctx) {
SourceRef sourceRef = createSourceRef(ctx);
model.getUnits().add(new SwitchExpressionBlockEnd(sourceRef));
verifySwitchExpressionBlock();
}

@Override
public void enterSwitchExpressionCase(RockerParser.SwitchExpressionCaseContext ctx) {

SourceRef sourceRef = createSourceRef(ctx);
final String text = ctx.CASE_EXPRESSION().getText();
final int idxFirst = text.indexOf('(');
final int idxLast = text.lastIndexOf(')');
final String expression = text.substring(idxFirst+1, idxLast );
model.getUnits().add(new SwitchCaseExpressionBlock(sourceRef, expression));

}

@Override
public void exitSwitchExpressionCase(RockerParser.SwitchExpressionCaseContext ctx) {
SourceRef sourceRef = createSourceRef(ctx);
model.getUnits().add(new SwitchCaseExpressionBlockEnd(sourceRef));
}

@Override
public void enterSwitchExpressionDefault(RockerParser.SwitchExpressionDefaultContext ctx) {
SourceRef sourceRef = createSourceRef(ctx);
model.getUnits().add(new SwitchDefaultExpressionBlock(sourceRef));
}

@Override
public void exitSwitchExpressionDefault(RockerParser.SwitchExpressionDefaultContext ctx) {
SourceRef sourceRef = createSourceRef(ctx);
model.getUnits().add(new SwitchDefaultExpressionBlockEnd(sourceRef));

}

private void verifySwitchBlock() {

List<TemplateUnit> units = this.model.getUnits();
Expand All @@ -971,6 +1020,27 @@ private void verifySwitchBlock() {
}
units.removeAll(toRemove);
}
private void verifySwitchExpressionBlock() {

List<TemplateUnit> units = this.model.getUnits();
List<TemplateUnit> toRemove=new ArrayList<>();
for (int i = 0, unitsSize = units.size(); i < unitsSize; i++) {
TemplateUnit unit = units.get(i);
if (unit instanceof PlainText) {
PlainText plain = (PlainText) unit;
if (inSwitchExpressionButNotCaseOrDefault(i)) {
if (plain.isWhitespace()) {
toRemove.add(unit);
} else {
// no plain allowed
SourcePosition pos = plain.findSourcePositionOfNonWhitespace();
throw new ParserRuntimeException(pos.getLineNumber(), pos.getPosInLine(), "plain text not allowed before end of switch block");
}
}
}
}
units.removeAll(toRemove);
}

private boolean inSwitchButNotCaseOrDefault(int i) {
for (int j = i; j >= 0; j--) {
Expand All @@ -984,6 +1054,18 @@ private boolean inSwitchButNotCaseOrDefault(int i) {
}
return false;
}
private boolean inSwitchExpressionButNotCaseOrDefault(int i) {
for (int j = i; j >= 0; j--) {
TemplateUnit templateUnit = model.getUnits().get(j);
if (templateUnit instanceof SwitchCaseExpressionBlockEnd || templateUnit instanceof SwitchDefaultExpressionBlockEnd || templateUnit instanceof SwitchExpressionBlock) {
return true;
}
if (templateUnit instanceof SwitchCaseExpressionBlock || templateUnit instanceof SwitchDefaultExpressionBlock || templateUnit instanceof SwitchExpressionBlockEnd) {
return false;
}
}
return false;
}

@Override
public void enterSwitchCase(RockerParser.SwitchCaseContext ctx) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2017 Fizzed Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fizzed.rocker.model;

/**
* Represents else-if part of an if block.
*/
public class SwitchCaseExpressionBlock extends BlockBegin {

public SwitchCaseExpressionBlock(final SourceRef sourceRef, final String expression) {
super(sourceRef, expression);
}
@Override
public boolean supportsSourceJournaling() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2015 Fizzed Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fizzed.rocker.model;

/**
*
* @author joelauer
*/
public class SwitchCaseExpressionBlockEnd extends BlockEnd {

public SwitchCaseExpressionBlockEnd(SourceRef sourceRef) {
super(sourceRef);
}
@Override
public boolean supportsSourceJournaling() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2017 Fizzed Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fizzed.rocker.model;

/**
* Represents else-if part of an if block.
*/
public class SwitchDefaultExpressionBlock extends BlockBegin {

public SwitchDefaultExpressionBlock(final SourceRef sourceRef) {
super(sourceRef,null );
}
@Override
public boolean supportsSourceJournaling() {
return false;
}
}
Loading

0 comments on commit 5246989

Please sign in to comment.