it is not required to place condition in parenthesis - '('?')'?- question marks mean “optional”.

trueStatement is meant to be evaluated when the condition is true.

the if can be followed by an else.

falseStatement is meant to be evaluated when the condition is false.

ifStatement is a statement too so it can be used in trueStatement or falseStatement (if … else if … else ).

New expression alternatives are pretty much self explanatory. Their purpose is to compare two expressions and return another expression (boolean value).

To better understand how the ‘if’ and ‘else’ can be used to specify ‘else if’ take a look at following snippet:

if(0){}elseif(1){}

The code is parsed to following parse tree:

As you can see the second if is actually a child of else. They are on the different level in hierarchy.
There is no need to specify ‘else if’ in rule explicitly. ifstatement rule is actually a statement rule too so other ifStatements
can be used inside ifStatement. This provides a way to chain them easily.

publicclassExpressionVisitorextendsEnkelBaseVisitor<Expression>{@OverridepublicConditionalExpressionvisitConditionalExpression(@NotNullEnkelParser.ConditionalExpressionContextctx){EnkelParser.ExpressionContextleftExpressionCtx=ctx.expression(0);//get left side expression ( ex. 1 < 5 -> it would mean get "1")EnkelParser.ExpressionContextrightExpressionCtx=ctx.expression(1);//get right side expressionExpressionleftExpression=leftExpressionCtx.accept(this);//get mapped (to POJO) left expression using this visitor//rightExpression might be null! Example: 'if (x)' checks x for nullity. The solution for this case is to assign integer 0 to the rightExpr ExpressionrightExpression=rightExpressionCtx!=null?rightExpressionCtx.accept(this):newValue(BultInType.INT,"0");CompareSigncmpSign=ctx.cmp!=null?CompareSign.fromString(ctx.cmp.getText()):CompareSign.NOT_EQUAL;//if there is no cmp sign use '!=0' by defaultreturnnewConditionalExpression(leftExpression,rightExpression,cmpSign);}}

Generating bytecode

The jvm has few groups of conditional instructions for conditional branching:

if<eq,ne,lt,le,gt,ge> - pops one value from the stack and comparse it to 0.

if_icmp_<eq,ne,lt,le,gt,ge> - pops two values from stack and compares them to each other.

ifs for other primitive types (lcmp - long ,fcmpg - float etc.)

if[non]null - checks for null

For now we’re just going to use second group.
The instructions take operand which is a branchoffset (the instruction to which proceed if the condition is met).

Generating ConditionalExpression

The first place the ifcmpne (compare two values for ‘not equal’ test) instruction is going to be used is
for generating bytecode is ConditionalExpression:

publicvoidgenerate(ConditionalExpressionconditionalExpression){ExpressionleftExpression=conditionalExpression.getLeftExpression();ExpressionrightExpression=conditionalExpression.getRightExpression();Typetype=leftExpression.getType();if(type!=rightExpression.getType()){thrownewComparisonBetweenDiferentTypesException(leftExpression,rightExpression);//not yet supported}leftExpression.accept(this);rightExpression.accept(this);CompareSigncompareSign=conditionalExpression.getCompareSign();LabeltrueLabel=newLabel();//represents an adress in code (to which jump if condition is met)LabelendLabel=newLabel();methodVisitor.visitJumpInsn(compareSign.getOpcode(),trueLabel);methodVisitor.visitInsn(Opcodes.ICONST_0);methodVisitor.visitJumpInsn(Opcodes.GOTO,endLabel);methodVisitor.visitLabel(trueLabel);methodVisitor.visitInsn(Opcodes.ICONST_1);methodVisitor.visitLabel(endLabel);}

Conditional instructions take operand which is a branchoffset (label).
Two values currently sitting at top of the stack are poped and compared using compareSign.getOpcode().

If the comparision is positive then the jump is performed to trueLabel.
The truLabel instructions consist of
methodVisitor.visitInsn(Opcodes.ICONST_1);.
This means pushing int 1 onto the stack.

If the comparison is negative no jump is performed.
Instead the next instruction is invoked (ICONST_0 - push 0 onto the stack).
Afterwards the GOTO (unconditional branching instruction) is performed to jump to endLabel.
That way the code responsible for positive comparision is bypassed.

Performing comparison in the manner described above guarantees that the result would be
1 or 0 (int value pushed onto the stack).

That way the conditonalExpression can be used as an expression - it can be assigned to a variable,
passed as argument to a function,printed or even returned.

The IfStatement relies on a concept used by ConditionalExpression - it
guarantees that the 0 or 1 is pushed onto the stack as result of generating.

It simply evaluates expression (condition.accept(expressionGenrator);)
and checks if the value it pushed onto the stack is != 0 (methodVisitor.visitJumpInsn(Opcodes.IFNE,trueLabel);).
If it is != 0 then it jumps to trueLabel which generates the trueStatement (ifStatement.getTrueStatement().accept(this);).
Otherwise it continues to execute instructions, by generating falseStatement, and jumping (GOTO) to the endLabel.