diff --git a/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/Redirected.java b/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/Redirected.java
index 6cfabe271..805c45bb5 100644
--- a/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/Redirected.java
+++ b/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/Redirected.java
@@ -17,6 +17,7 @@
import com.helger.jcodemodel.IJFormatter;
import com.helger.jcodemodel.JBlock;
import com.helger.jcodemodel.JCatchBlock;
+import com.helger.jcodemodel.JOp;
import com.helger.jcodemodel.vars.JCatchFormalParameter;
public class Redirected {
@@ -73,6 +74,10 @@ public void generate(IJFormatter arg0) {
jCatchBlock.generate(arg0);
}
+ public JOp.Precedence operatorPrecedence() {
+ return jCatchBlock.operatorPrecedence();
+ }
+
public JCatchFormalParameter param() {
return jCatchBlock.param();
}
diff --git a/examples/pom.xml b/examples/pom.xml
index 566ca2283..47f153612 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -28,6 +28,7 @@
POM module for all the examples modules
+ settings
plugins
diff --git a/examples/settings/example-settings.json b/examples/settings/example-settings.json
new file mode 100644
index 000000000..900188840
--- /dev/null
+++ b/examples/settings/example-settings.json
@@ -0,0 +1,68 @@
+{
+ "indent" : {
+ "string" : " ",
+ "tabSize" : 4
+ },
+ "parentheses" : {
+ "global" : "REQUIRED"
+ },
+ "wrap" : {
+ "lineWidth" : 80,
+ "disabled" : false,
+ "catchClause" : {
+ "types" : {
+ "condition" : "NEVER",
+ "indent" : 1,
+ "wrapAfterSep" : true
+ }
+ },
+ "forLoop" : {
+ "init" : {
+ "condition" : "NEVER",
+ "indent" : 1,
+ "wrapAfterSep" : true
+ }
+ },
+ "method" : {
+ "type" : {
+ "condition" : "NEVER",
+ "indent" : 1
+ },
+ "name" : {
+ "condition" : "NEVER",
+ "indent" : 1
+ },
+ "params" : {
+ "condition" : "PAST3",
+ "indent" : 1,
+ "wrapAfterSep" : true
+ },
+ "bracket" : {
+ "condition" : "NEVER",
+ "indent" : 0
+ },
+ "args" : {
+ "condition" : "PAST3",
+ "indent" : 1,
+ "wrapAfterSep" : true
+ }
+ },
+ "variables" : {
+ "array" : {
+ "condition" : "REQUIRED",
+ "indent" : 1,
+ "wrapAfterSep" : true
+ },
+ "block" : {
+ "condition" : "REQUIRED",
+ "indent" : 1,
+ "wrapAfterSep" : true
+ },
+ "field" : {
+ "condition" : "REQUIRED",
+ "indent" : 1,
+ "wrapAfterSep" : true
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/settings/example-settings.yaml b/examples/settings/example-settings.yaml
new file mode 100644
index 000000000..eb5a28f06
--- /dev/null
+++ b/examples/settings/example-settings.yaml
@@ -0,0 +1,49 @@
+indent:
+ string: " "
+ tabSize: 4
+parentheses:
+ global: "REQUIRED"
+wrap:
+ lineWidth: 80
+ disabled: false
+ catchClause:
+ types:
+ condition: "NEVER"
+ indent: 1
+ wrapAfterSep: true
+ forLoop:
+ init:
+ condition: "NEVER"
+ indent: 1
+ wrapAfterSep: true
+ method:
+ type:
+ condition: "NEVER"
+ indent: 1
+ name:
+ condition: "NEVER"
+ indent: 1
+ params:
+ condition: "PAST3"
+ indent: 1
+ wrapAfterSep: true
+ bracket:
+ condition: "NEVER"
+ indent: 0
+ args:
+ condition: "PAST3"
+ indent: 1
+ wrapAfterSep: true
+ variables:
+ array:
+ condition: "REQUIRED"
+ indent: 1
+ wrapAfterSep: true
+ block:
+ condition: "REQUIRED"
+ indent: 1
+ wrapAfterSep: true
+ field:
+ condition: "REQUIRED"
+ indent: 1
+ wrapAfterSep: true
diff --git a/examples/settings/pom.xml b/examples/settings/pom.xml
new file mode 100644
index 000000000..73ed90137
--- /dev/null
+++ b/examples/settings/pom.xml
@@ -0,0 +1,38 @@
+
+
+
+ 4.0.0
+
+ com.helger.jcodemodel
+ examples
+ 4.3.1-SNAPSHOT
+
+ com.helger.jcodemodel.examples
+ settings
+ LIB Settings Examples
+ shows setting examples
+
+
+ 2.20.1
+
+
+
+
+ junit
+ junit
+ test
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+ ${jackson.version}
+
+
+ com.helger.jcodemodel.plugin.generators
+ json
+ ${project.version}
+
+
+
diff --git a/examples/settings/src/test/java/com/helger/jcodemodel/example/settings/ExportSettingsTest.java b/examples/settings/src/test/java/com/helger/jcodemodel/example/settings/ExportSettingsTest.java
new file mode 100644
index 000000000..2038d2af7
--- /dev/null
+++ b/examples/settings/src/test/java/com/helger/jcodemodel/example/settings/ExportSettingsTest.java
@@ -0,0 +1,60 @@
+package com.helger.jcodemodel.example.settings;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.util.DefaultIndenter;
+import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature;
+import com.helger.jcodemodel.writer.FormatterSettings;
+
+/// Actually not a test, but export the default formatter settings so people
+/// have an idea of the settings available.
+/// The yaml and json files are exported at the project root.
+public class ExportSettingsTest {
+
+ @Test
+ public void writeYaml() {
+ FormatterSettings export = new FormatterSettings();
+
+ YAMLFactory f =
+ new YAMLFactory()
+ .disable(Feature.WRITE_DOC_START_MARKER);
+ ObjectMapper om = new ObjectMapper(f);
+
+ File out = new File("example-settings.yaml");
+ try (FileWriter writer = new FileWriter(out)) {
+ om.writer().writeValue(writer, export);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Test
+ public void writeJson() {
+ FormatterSettings export = new FormatterSettings();
+
+ DefaultPrettyPrinter prettyPrinter =
+ new DefaultPrettyPrinter()
+ .withObjectIndenter(new DefaultIndenter().withLinefeed("\n"));
+ ObjectMapper om =
+ new ObjectMapper()
+ .setDefaultPrettyPrinter(prettyPrinter)
+ .enable(SerializationFeature.INDENT_OUTPUT);
+
+ File out = new File("example-settings.json");
+ try (FileWriter writer = new FileWriter(out)) {
+ om.writer().writeValue(writer, export);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/IJExpression.java b/jcodemodel/src/main/java/com/helger/jcodemodel/IJExpression.java
index d41d4f41b..f0bba5bbf 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/IJExpression.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/IJExpression.java
@@ -807,4 +807,5 @@ default JCast castTo (@NonNull final AbstractJType aType)
{
return JExpr.cast (aType, this);
}
+
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/IJGenerable.java b/jcodemodel/src/main/java/com/helger/jcodemodel/IJGenerable.java
index 583c26fd3..d85a64419 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/IJGenerable.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/IJGenerable.java
@@ -42,10 +42,28 @@
import org.jspecify.annotations.NonNull;
+import com.helger.jcodemodel.JOp.Precedence;
+
/**
* Common interface for code components that can generate uses of themselves.
*/
public interface IJGenerable extends IJObject
{
void generate (@NonNull IJFormatter f);
+
+ /// Indicates the operator precedence at which an operator addition can change the meaning of
+ /// this. Used to check the need for parentheses.
+ ///
+ /// For example, an "a+b*c" element would return the precedence of "+", and any operator with
+ /// an higher precedence could break it : a "++" operator would require parentheses since
+ /// "a+b*c++" is not the same as "(a+b*c)++"
+ ///
+ /// Most elements are not operator-sensitive so the default is the max precedence (token). For
+ /// example method call( "myFunction()" )
+ ///
+ /// @return the lowest operator precedence.
+ default JOp.Precedence operatorPrecedence ()
+ {
+ return Precedence.TOKEN;
+ }
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JArrayCompRef.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JArrayCompRef.java
index f0d83dbc7..1338fb1b8 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JArrayCompRef.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JArrayCompRef.java
@@ -46,6 +46,7 @@
import com.helger.base.enforce.ValueEnforcer;
import com.helger.base.equals.EqualsHelper;
+import com.helger.jcodemodel.JOp.Precedence;
/**
* array component reference.
@@ -92,7 +93,30 @@ public IJExpression index ()
public void generate (@NonNull final IJFormatter f)
{
- f.generable (m_aArray).print ('[').generable (m_aIndex).print (']');
+ boolean parentheses = true;
+ switch (f.settings ().parentheses.global)
+ {
+ case ALWAYS ->
+ {
+ parentheses = true;
+ }
+ case NOTOKEN ->
+ {
+ parentheses = m_aArray.operatorPrecedence () != Precedence.TOKEN;
+ }
+ case REQUIRED ->
+ {
+ parentheses = Precedence.DEREF.higherThan (m_aArray.operatorPrecedence ());
+ }
+ default -> throw new IllegalArgumentException ("Unexpected value: " + f.settings ().parentheses.global);
+ }
+
+ if (parentheses)
+ f.print ('(');
+ f.generable (m_aArray);
+ if (parentheses)
+ f.print (')');
+ f.print ('[').generable (m_aIndex).print (']');
}
@Override
@@ -111,4 +135,10 @@ public int hashCode ()
{
return getHashCode (this, m_aArray, m_aIndex);
}
+
+ @Override
+ public Precedence operatorPrecedence ()
+ {
+ return Precedence.DEREF;
+ }
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JAssignment.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JAssignment.java
index db8626983..4dd533d59 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JAssignment.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JAssignment.java
@@ -45,6 +45,7 @@
import org.jspecify.annotations.NonNull;
import com.helger.base.equals.EqualsHelper;
+import com.helger.jcodemodel.JOp.Precedence;
/**
* Assignment statements, which are also expressions.
@@ -119,7 +120,31 @@ public String opFull ()
public void generate (@NonNull final IJFormatter f)
{
- f.generable (m_aLhs).print (opFull ()).generable (m_aRhs);
+ // only right side may need parentheses
+ boolean parentheses = true;
+ switch (f.settings ().parentheses.global)
+ {
+ case ALWAYS ->
+ {
+ parentheses = true;
+ }
+ case NOTOKEN ->
+ {
+ parentheses = m_aRhs.operatorPrecedence () != Precedence.TOKEN;
+ }
+ case REQUIRED ->
+ {
+ // basically only lambdas need to be parenthesized
+ parentheses = Precedence.ASSIGNMENT.higherThan (m_aRhs.operatorPrecedence ());
+ }
+ default -> throw new IllegalArgumentException ("Unexpected value: " + f.settings ().parentheses.global);
+ }
+ f.generable (m_aLhs).print (opFull ());
+ if (parentheses)
+ f.print ('(');
+ f.generable (m_aRhs);
+ if (parentheses)
+ f.print (')');
}
public void state (@NonNull final IJFormatter f)
@@ -145,4 +170,10 @@ public int hashCode ()
{
return getHashCode (this, m_aLhs, m_aRhs, m_sOperator);
}
+
+ @Override
+ public Precedence operatorPrecedence ()
+ {
+ return Precedence.ASSIGNMENT;
+ }
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JCast.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JCast.java
index c25976309..0e9faac5c 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JCast.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JCast.java
@@ -45,6 +45,7 @@
import org.jspecify.annotations.NonNull;
import com.helger.base.equals.EqualsHelper;
+import com.helger.jcodemodel.JOp.Precedence;
/**
* A cast operation.
@@ -89,7 +90,30 @@ public IJExpression object ()
public void generate (@NonNull final IJFormatter f)
{
- f.print ("((").generable (m_aType).print (')').generable (m_aObject).print (')');
+ boolean parentheses = true;
+ switch (f.settings ().parentheses.global)
+ {
+ case ALWAYS ->
+ {
+ parentheses = true;
+ }
+ case NOTOKEN ->
+ {
+ parentheses = m_aObject.operatorPrecedence () != Precedence.TOKEN;
+ }
+ case REQUIRED ->
+ {
+ parentheses = Precedence.CAST.higherThan (m_aObject.operatorPrecedence ());
+ }
+ default -> throw new IllegalArgumentException ("Unexpected value: " + f.settings ().parentheses.global);
+ }
+
+ f.print ("(").generable (m_aType).print (')');
+ if (parentheses)
+ f.print ('(');
+ f.generable (m_aObject);
+ if (parentheses)
+ f.print (')');
}
@Override
@@ -109,4 +133,10 @@ public int hashCode ()
{
return getHashCode (this, m_aType.fullName (), m_aObject);
}
+
+ @Override
+ public Precedence operatorPrecedence ()
+ {
+ return Precedence.CAST;
+ }
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JConditional.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JConditional.java
index 95c5be478..92681b63f 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JConditional.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JConditional.java
@@ -133,14 +133,14 @@ public void state (@NonNull final IJFormatter f)
return;
}
- if (JOp.hasTopOp (m_aTestExpr))
- {
- f.print ("if ").generable (m_aTestExpr);
- }
- else
- {
+ // if (JOp.hasTopOp (m_aTestExpr))
+ // {
+ // f.print ("if ").generable (m_aTestExpr);
+ // }
+ // else
+ // {
f.print ("if (").generable (m_aTestExpr).print (')');
- }
+ // }
f.generable (m_aThenBlock);
if (m_aElseBlock != null)
f.print ("else").generable (m_aElseBlock);
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JExpr.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JExpr.java
index 31ad0e287..387b9b7ea 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JExpr.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JExpr.java
@@ -149,25 +149,25 @@ public static JAssignment assignBor (@NonNull final IJAssignmentTarget aLhs, @No
}
@NonNull
- public static JOpUnaryTight incr (@NonNull final IJExpression aExpr)
+ public static JOpUnary incr (@NonNull final IJExpression aExpr)
{
return JOp.postincr (aExpr);
}
@NonNull
- public static JOpUnaryTight preincr (@NonNull final IJExpression aExpr)
+ public static JOpUnary preincr (@NonNull final IJExpression aExpr)
{
return JOp.preincr (aExpr);
}
@NonNull
- public static JOpUnaryTight decr (@NonNull final IJExpression aExpr)
+ public static JOpUnary decr (@NonNull final IJExpression aExpr)
{
return JOp.postdecr (aExpr);
}
@NonNull
- public static JOpUnaryTight predecr (@NonNull final IJExpression aExpr)
+ public static JOpUnary predecr (@NonNull final IJExpression aExpr)
{
return JOp.predecr (aExpr);
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JForLoop.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JForLoop.java
index a42b46810..183e9a624 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JForLoop.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JForLoop.java
@@ -51,12 +51,22 @@
import com.helger.jcodemodel.vars.JBlockVar;
/**
- * For statement
+ * For statement.
+ *
+ *
+ * for ([expression]+|[variablelist]? ; [test]? ; [updateStatement]+ )
+ *
+ *
+ * The init must be either called once to create a variable, or one+ times to add init
+ * expressions.
+ * To create multiple init variables, init the first one and use it to add new ones with the same
+ * type or array types
+ *
*/
public class JForLoop implements IJStatement
{
- // either a init var, or expressions
+ // this class contains either a init var, or expressions
private JBlockVar m_aInitVar;
private final List m_aInitExprs = new ArrayList <> ();
private IJExpression m_aTestExpr;
@@ -87,6 +97,7 @@ protected void checkInitExpr ()
throw new IllegalStateException ("a for loop must have either variable declaration or expressions, this already has variable");
}
+ /// set the base variable init with a modifier (limited to variable modifiers, so final)
@NonNull
public JBlockVar init (final int nMods,
@NonNull final AbstractJType aType,
@@ -99,6 +110,8 @@ public JBlockVar init (final int nMods,
return aVar;
}
+ /// set the base variable init. `for(int i=0 ; ; )`
+ /// @return a new variable. You can use it to add sub variables, eg `for(int i=0, j=i ; ;)`
@NonNull
public JBlockVar init (@NonNull final AbstractJType aType,
@NonNull final String sVarName,
@@ -107,11 +120,15 @@ public JBlockVar init (@NonNull final AbstractJType aType,
return init (JMod.NONE, aType, sVarName, aInitExpr);
}
+ /// add an assignment expression to the init list.
+ @NonNull
public JForLoop init (@NonNull final JVar aVar, @NonNull final IJExpression aRhs)
{
return init (JExpr.assign (aVar, aRhs));
}
+ /// add an init expression to the init list
+ @NonNull
public JForLoop init (IJExpression ije)
{
checkInitExpr ();
@@ -148,6 +165,7 @@ public IJExpression test ()
return m_aTestExpr;
}
+ /// add an update statement to the list of existing ones.
public void update (@NonNull final IJExpression aUpdate)
{
ValueEnforcer.notNull (aUpdate, "Update");
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JOp.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JOp.java
index 87e174554..8a824d3a6 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JOp.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JOp.java
@@ -44,6 +44,9 @@
import org.jspecify.annotations.Nullable;
import com.helger.annotation.concurrent.Immutable;
+import com.helger.jcodemodel.JOpBinary.BinaryOp;
+import com.helger.jcodemodel.JOpTernary.TernaryOp;
+import com.helger.jcodemodel.JOpUnary.UnaryOp;
/**
* Class for generating expressions containing operators
@@ -56,6 +59,47 @@ public final class JOp
private JOp ()
{}
+ /// expression precedence. Lower position means higher priority.
+ ///
+ /// @see https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
+ /// @see https://introcs.cs.princeton.edu/java/11precedence/
+ public static enum Precedence
+ {
+ TOKEN, // 12, myVar . Not an operator, but required for JExpr precedence.
+ DEREF, // (a), [a], a.b
+ POSTFIX, // a ++
+ UNARY, // ++a, ! a, -a
+ CAST, // (a) b
+ MULTIPLICATIVE, // a * b, a / b
+ ADDITIVE, // a + b
+ SHIFT, // a >> b
+ RELATIONAL, // a > b, a instanceof b
+ EQUALITY, // a == b, a != b
+ BITWISE_AND, // a & b
+ BITWISE_XOR, // a ^ b
+ BITWISE_OR, // a | b
+ LOGICAL_AND, // a && b
+ LOGICAL_OR, // a || b
+ TERNAY, // a ? b : c
+ ASSIGNMENT, // a=b, a += b
+ LAMBDA // a -> b
+ ;
+
+ public Precedence lowest (Precedence other)
+ {
+ if (other == null)
+ return this;
+ if (other.ordinal () < ordinal ())
+ return other;
+ return this;
+ }
+
+ public boolean higherThan (@NonNull Precedence other)
+ {
+ return ordinal () < other.ordinal ();
+ }
+ }
+
/**
* Determine whether the top level of an expression involves an operator.
*
@@ -73,7 +117,7 @@ public static boolean hasTopOp (@Nullable final IJExpression aExpr)
@NonNull
public static JOpUnary minus (@NonNull final IJExpression aExpr)
{
- return new JOpUnary ("-", aExpr);
+ return new JOpUnary (UnaryOp.MINUS, aExpr);
}
/**
@@ -91,13 +135,13 @@ public static IJExpression not (@NonNull final IJExpression aExpr)
return JExpr.FALSE;
if (aExpr == JExpr.FALSE)
return JExpr.TRUE;
- return new JOpUnary ("!", aExpr);
+ return new JOpUnary (UnaryOp.LOGICAL_NOT, aExpr);
}
@NonNull
public static JOpUnary complement (@NonNull final IJExpression aExpr)
{
- return new JOpUnary ("~", aExpr);
+ return new JOpUnary (UnaryOp.BITWISE_NOT, aExpr);
}
/**
@@ -108,9 +152,9 @@ public static JOpUnary complement (@NonNull final IJExpression aExpr)
* @return aExpr++
*/
@NonNull
- public static JOpUnaryTight postincr (@NonNull final IJExpression aExpr)
+ public static JOpUnary postincr (@NonNull final IJExpression aExpr)
{
- return new JOpUnaryTight (aExpr, "++");
+ return new JOpUnary (UnaryOp.POST_INCR, aExpr);
}
/**
@@ -121,9 +165,9 @@ public static JOpUnaryTight postincr (@NonNull final IJExpression aExpr)
* @return ++aExpr
*/
@NonNull
- public static JOpUnaryTight preincr (@NonNull final IJExpression aExpr)
+ public static JOpUnary preincr (@NonNull final IJExpression aExpr)
{
- return new JOpUnaryTight ("++", aExpr);
+ return new JOpUnary (UnaryOp.PRE_INCR, aExpr);
}
/**
@@ -134,9 +178,9 @@ public static JOpUnaryTight preincr (@NonNull final IJExpression aExpr)
* @return aExpr--
*/
@NonNull
- public static JOpUnaryTight postdecr (@NonNull final IJExpression aExpr)
+ public static JOpUnary postdecr (@NonNull final IJExpression aExpr)
{
- return new JOpUnaryTight (aExpr, "--");
+ return new JOpUnary (UnaryOp.POST_DECR, aExpr);
}
/**
@@ -147,9 +191,9 @@ public static JOpUnaryTight postdecr (@NonNull final IJExpression aExpr)
* @return --aExpr
*/
@NonNull
- public static JOpUnaryTight predecr (@NonNull final IJExpression aExpr)
+ public static JOpUnary predecr (@NonNull final IJExpression aExpr)
{
- return new JOpUnaryTight ("--", aExpr);
+ return new JOpUnary (UnaryOp.PRE_DECR, aExpr);
}
/* -- Binary operators -- */
@@ -157,61 +201,61 @@ public static JOpUnaryTight predecr (@NonNull final IJExpression aExpr)
@NonNull
public static JOpBinary plus (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "+", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.ADD, aRhs);
}
@NonNull
public static JOpBinary minus (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "-", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.SUBSTRACT, aRhs);
}
@NonNull
public static JOpBinary mul (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "*", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.MULTIPLY, aRhs);
}
@NonNull
public static JOpBinary div (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "/", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.DIVIDE, aRhs);
}
@NonNull
public static JOpBinary mod (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "%", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.MODULUS, aRhs);
}
@NonNull
public static JOpBinary shl (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "<<", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.SHIFT_LEFT, aRhs);
}
@NonNull
public static JOpBinary shr (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, ">>", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.SHIFT_RIGHT, aRhs);
}
@NonNull
public static JOpBinary shrz (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, ">>>", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.SHIFT_RIGHT_ZERO, aRhs);
}
@NonNull
public static JOpBinary band (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "&", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.BITWISE_AND, aRhs);
}
@NonNull
public static JOpBinary bor (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "|", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.BITWISE_OR, aRhs);
}
@NonNull
@@ -226,7 +270,7 @@ public static IJExpression cand (@NonNull final IJExpression aLhs, @NonNull fina
return aLhs; // JExpr.FALSE
if (aRhs == JExpr.FALSE)
return aRhs; // JExpr.FALSE
- return new JOpBinary (aLhs, "&&", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.LOGICAL_AND, aRhs);
}
@NonNull
@@ -240,55 +284,55 @@ public static IJExpression cor (@NonNull final IJExpression aLhs, @NonNull final
return aRhs;
if (aRhs == JExpr.FALSE)
return aLhs;
- return new JOpBinary (aLhs, "||", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.LOGICAL_OR, aRhs);
}
@NonNull
public static JOpBinary xor (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "^", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.BITWISE_XOR, aRhs);
}
@NonNull
public static JOpBinary lt (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "<", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.LOWER, aRhs);
}
@NonNull
public static JOpBinary lte (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "<=", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.LOWER_EQUAL, aRhs);
}
@NonNull
public static JOpBinary gt (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, ">", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.GREATER, aRhs);
}
@NonNull
public static JOpBinary gte (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, ">=", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.GREATER_EQUAL, aRhs);
}
@NonNull
public static JOpBinary eq (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "==", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.EQUALS, aRhs);
}
@NonNull
public static JOpBinary ne (@NonNull final IJExpression aLhs, @NonNull final IJExpression aRhs)
{
- return new JOpBinary (aLhs, "!=", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.NOT_EQUALS, aRhs);
}
@NonNull
public static JOpBinary _instanceof (@NonNull final IJExpression aLhs, @NonNull final AbstractJType aRhs)
{
- return new JOpBinary (aLhs, "instanceof", aRhs);
+ return new JOpBinary (aLhs, BinaryOp.INSTANCE_OF, aRhs);
}
/* -- Ternary operators -- */
@@ -298,6 +342,6 @@ public static JOpTernary cond (@NonNull final IJExpression aCond,
@NonNull final IJExpression aIfTrue,
@NonNull final IJExpression aIfFalse)
{
- return new JOpTernary (aCond, "?", aIfTrue, ":", aIfFalse);
+ return new JOpTernary (TernaryOp.TERN_COND, aCond, aIfTrue, aIfFalse);
}
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JOpBinary.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JOpBinary.java
index f54c34c91..71e428edf 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JOpBinary.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JOpBinary.java
@@ -46,19 +46,58 @@
import com.helger.base.enforce.ValueEnforcer;
import com.helger.base.equals.EqualsHelper;
+import com.helger.jcodemodel.JOp.Precedence;
public class JOpBinary implements IJExpression
{
+
+ /// binary operators, their print string and their precedence
+ ///
+ /// use BinaryOp since BinaryOperator exists in the jdk.
+ public static enum BinaryOp
+ {
+ ADD ("+", Precedence.ADDITIVE),
+ BITWISE_AND ("&", Precedence.BITWISE_AND),
+ BITWISE_OR ("|", Precedence.BITWISE_OR),
+ BITWISE_XOR ("^", Precedence.BITWISE_XOR),
+ DIVIDE ("/", Precedence.MULTIPLICATIVE),
+ EQUALS ("==", Precedence.EQUALITY),
+ GREATER (">", Precedence.RELATIONAL),
+ GREATER_EQUAL (">=", Precedence.RELATIONAL),
+ INSTANCE_OF ("instanceof", Precedence.RELATIONAL),
+ LOGICAL_AND ("&&", Precedence.LOGICAL_AND),
+ LOGICAL_OR ("||", Precedence.LOGICAL_OR),
+ LOWER ("<", Precedence.RELATIONAL),
+ LOWER_EQUAL ("<=", Precedence.RELATIONAL),
+ MODULUS ("%", Precedence.MULTIPLICATIVE),
+ MULTIPLY ("*", Precedence.MULTIPLICATIVE),
+ NOT_EQUALS ("!=", Precedence.EQUALITY),
+ SHIFT_LEFT ("<<", Precedence.SHIFT),
+ SHIFT_RIGHT (">>", Precedence.SHIFT),
+ SHIFT_RIGHT_ZERO (">>>", Precedence.SHIFT),
+ SUBSTRACT ("-", Precedence.ADDITIVE);
+
+ public final String print;
+ public final Precedence precedence;
+
+ BinaryOp (String print, Precedence precedence)
+ {
+ this.print = print;
+ this.precedence = precedence;
+ }
+ }
+
private final IJExpression m_aLeft;
- private final String m_sOperator;
+ @NonNull
+ private final BinaryOp m_aOperator;
private final IJGenerable m_aRight;
protected JOpBinary (@NonNull final IJExpression aLeft,
- @NonNull final String sOperator,
+ @NonNull final BinaryOp aOperator,
@NonNull final IJGenerable aRight)
{
m_aLeft = ValueEnforcer.notNull (aLeft, "Left");
- m_sOperator = ValueEnforcer.notNull (sOperator, "Operator");
+ m_aOperator = ValueEnforcer.notNull (aOperator, "Operator");
m_aRight = ValueEnforcer.notNull (aRight, "Right");
}
@@ -71,7 +110,7 @@ public IJExpression left ()
@NonNull
public String op ()
{
- return m_sOperator;
+ return m_aOperator.print;
}
@NonNull
@@ -82,7 +121,36 @@ public IJGenerable right ()
public void generate (@NonNull final IJFormatter f)
{
- f.print ('(').generable (m_aLeft).print (m_sOperator).generable (m_aRight).print (')');
+ boolean leftParentheses = true, rightParentheses = true;
+ switch(f.settings ().parentheses.global) {
+ case ALWAYS ->
+ {
+ leftParentheses = true;
+ rightParentheses = true;
+ }
+ case NOTOKEN ->
+ {
+ leftParentheses = m_aLeft.operatorPrecedence () != Precedence.TOKEN;
+ rightParentheses = m_aRight.operatorPrecedence () != Precedence.TOKEN;
+ }
+ case REQUIRED ->
+ {
+ leftParentheses = m_aOperator.precedence.higherThan (m_aLeft.operatorPrecedence ());
+ rightParentheses = m_aOperator.precedence.higherThan (m_aRight.operatorPrecedence ());
+ }
+ default -> throw new IllegalArgumentException ("Unexpected value: " + f.settings ().parentheses.global);
+ }
+ if (leftParentheses)
+ f.print ('(');
+ f.generable (m_aLeft);
+ if (leftParentheses)
+ f.print (')');
+ f.print (m_aOperator.print);
+ if (rightParentheses)
+ f.print ('(');
+ f.generable (m_aRight);
+ if (rightParentheses)
+ f.print (')');
}
@Override
@@ -94,13 +162,19 @@ public boolean equals (final Object o)
return false;
final JOpBinary rhs = (JOpBinary) o;
return EqualsHelper.equals (m_aLeft, rhs.m_aLeft) &&
- EqualsHelper.equals (m_sOperator, rhs.m_sOperator) &&
+ EqualsHelper.equals (m_aOperator, rhs.m_aOperator) &&
EqualsHelper.equals (m_aRight, rhs.m_aRight);
}
@Override
public int hashCode ()
{
- return getHashCode (this, m_aLeft, m_sOperator, m_aRight);
+ return getHashCode (this, m_aLeft, m_aOperator, m_aRight);
+ }
+
+ @Override
+ public Precedence operatorPrecedence ()
+ {
+ return m_aOperator.precedence;
}
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JOpTernary.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JOpTernary.java
index a506a0c38..722e06708 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JOpTernary.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JOpTernary.java
@@ -46,25 +46,43 @@
import com.helger.base.enforce.ValueEnforcer;
import com.helger.base.equals.EqualsHelper;
+import com.helger.jcodemodel.JOp.Precedence;
public class JOpTernary implements IJExpression
{
+
+ /// ternary operators, their print strings and their precedences
+ public static enum TernaryOp
+ {
+ TERN_COND ("?", Precedence.TERNAY, ":", Precedence.TERNAY)
+ ;
+
+ public final String leftPrint, rightPrint;
+ public final Precedence leftPrecedence, rightPrecedence;
+
+ TernaryOp (String leftPrint, Precedence leftPrecedence, String rightPrint, Precedence rightPrecedence)
+ {
+ this.leftPrint = leftPrint;
+ this.leftPrecedence = leftPrecedence;
+ this.rightPrint = rightPrint;
+ this.rightPrecedence = rightPrecedence;
+ }
+
+ }
+
+ private final TernaryOp m_aOperator;
private final IJExpression m_aExpr1;
- private final String m_sOperator1;
private final IJExpression m_aExpr2;
- private final String m_sOperator2;
private final IJExpression m_aExpr3;
- protected JOpTernary (@NonNull final IJExpression aExpr1,
- @NonNull final String sOperator1,
+ protected JOpTernary (@NonNull TernaryOp operator,
+ @NonNull final IJExpression aExpr1,
@NonNull final IJExpression aExpr2,
- @NonNull final String sOperator2,
@NonNull final IJExpression aExpr3)
{
+ m_aOperator = operator;
m_aExpr1 = ValueEnforcer.notNull (aExpr1, "Expr1");
- m_sOperator1 = ValueEnforcer.notNull (sOperator1, "Operator1");
m_aExpr2 = ValueEnforcer.notNull (aExpr2, "Expr2");
- m_sOperator2 = ValueEnforcer.notNull (sOperator2, "Operator2");
m_aExpr3 = ValueEnforcer.notNull (aExpr3, "Expr3");
}
@@ -77,7 +95,7 @@ public IJExpression expr1 ()
@NonNull
public String op1 ()
{
- return m_sOperator1;
+ return m_aOperator.leftPrint;
}
@NonNull
@@ -89,7 +107,7 @@ public IJGenerable expr2 ()
@NonNull
public String op2 ()
{
- return m_sOperator2;
+ return m_aOperator.rightPrint;
}
@NonNull
@@ -100,13 +118,50 @@ public IJGenerable expr3 ()
public void generate (@NonNull final IJFormatter f)
{
- f.print ('(')
- .generable (m_aExpr1)
- .print (m_sOperator1)
- .generable (m_aExpr2)
- .print (m_sOperator2)
- .generable (m_aExpr3)
- .print (')');
+ boolean leftParentheses = true, midParentheses = true, rightParentheses = true;
+ switch (f.settings ().parentheses.global)
+ {
+ case ALWAYS ->
+ {
+ leftParentheses = true;
+ midParentheses = true;
+ rightParentheses = true;
+ }
+ case NOTOKEN ->
+ {
+ leftParentheses = m_aExpr1.operatorPrecedence () != Precedence.TOKEN;
+ midParentheses = m_aExpr2.operatorPrecedence () != Precedence.TOKEN;
+ rightParentheses = m_aExpr3.operatorPrecedence () != Precedence.TOKEN;
+ }
+ case REQUIRED ->
+ {
+ leftParentheses = !m_aExpr1.operatorPrecedence ().higherThan (m_aOperator.leftPrecedence);
+ midParentheses = !m_aExpr2.operatorPrecedence ().higherThan (m_aOperator.leftPrecedence) ||
+ !m_aExpr2.operatorPrecedence ().higherThan (m_aOperator.rightPrecedence);
+ rightParentheses = !m_aExpr3.operatorPrecedence ().higherThan (m_aOperator.rightPrecedence);
+ }
+ }
+ if (leftParentheses)
+ f.print ('(');
+ f.generable (m_aExpr1);
+ if (leftParentheses)
+ f.print (')');
+
+ f.print (m_aOperator.leftPrint);
+
+ if (midParentheses)
+ f.print ('(');
+ f.generable (m_aExpr2);
+ if (midParentheses)
+ f.print (')');
+
+ f.print (m_aOperator.rightPrint);
+
+ if (rightParentheses)
+ f.print ('(');
+ f.generable (m_aExpr3);
+ if (rightParentheses)
+ f.print (')');
}
@Override
@@ -117,16 +172,21 @@ public boolean equals (final Object o)
if (o == null || getClass () != o.getClass ())
return false;
final JOpTernary rhs = (JOpTernary) o;
- return EqualsHelper.equals (m_aExpr1, rhs.m_aExpr1) &&
- EqualsHelper.equals (m_sOperator1, rhs.m_sOperator1) &&
+ return EqualsHelper.equals (m_aOperator, rhs.m_aOperator) &&
+ EqualsHelper.equals (m_aExpr1, rhs.m_aExpr1) &&
EqualsHelper.equals (m_aExpr2, rhs.m_aExpr2) &&
- EqualsHelper.equals (m_sOperator2, rhs.m_sOperator2) &&
EqualsHelper.equals (m_aExpr3, rhs.m_aExpr3);
}
@Override
public int hashCode ()
{
- return getHashCode (this, m_aExpr1, m_sOperator1, m_aExpr2, m_sOperator2, m_aExpr3);
+ return getHashCode (this, m_aExpr1, m_aOperator, m_aExpr2, m_aExpr3);
+ }
+
+ @Override
+ public Precedence operatorPrecedence ()
+ {
+ return m_aOperator.leftPrecedence.lowest (m_aOperator.rightPrecedence);
}
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JOpUnary.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JOpUnary.java
index 331c1cece..46cb4be6a 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JOpUnary.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/JOpUnary.java
@@ -46,12 +46,37 @@
import com.helger.base.enforce.ValueEnforcer;
import com.helger.base.equals.EqualsHelper;
+import com.helger.jcodemodel.JOp.Precedence;
public class JOpUnary implements IJExpression
{
- private final String m_sOperator;
+ /// unary operators, their print string and their precedence
+ public static enum UnaryOp
+ {
+ BITWISE_NOT ("~", Precedence.UNARY, true),
+ LOGICAL_NOT ("!", Precedence.UNARY, true),
+ MINUS ("-", Precedence.UNARY, true),
+ POST_DECR ("--", Precedence.POSTFIX, false),
+ POST_INCR ("++", Precedence.POSTFIX, false),
+ PRE_DECR ("--", Precedence.POSTFIX, true),
+ PRE_INCR ("++", Precedence.POSTFIX, true),
+ ;
+
+ public final String print;
+ public final Precedence precedence;
+ public final boolean prefix;
+
+ UnaryOp (String print, Precedence precedence, boolean prefix)
+ {
+ this.print = print;
+ this.precedence = precedence;
+ this.prefix = prefix;
+ }
+
+ }
+
+ private final UnaryOp m_aOperator;
private final IJExpression m_aExpr;
- private final boolean m_bOperatorComesFirst;
/**
* Constructor for operator before expression
@@ -61,32 +86,16 @@ public class JOpUnary implements IJExpression
* @param aExpr
* expression
*/
- protected JOpUnary (@NonNull final String sOperator, @NonNull final IJExpression aExpr)
+ protected JOpUnary (@NonNull final UnaryOp aOperator, @NonNull final IJExpression aExpr)
{
- m_sOperator = ValueEnforcer.notNull (sOperator, "Operator");
+ m_aOperator = ValueEnforcer.notNull (aOperator, "Operator");
m_aExpr = ValueEnforcer.notNull (aExpr, "Expression");
- m_bOperatorComesFirst = true;
- }
-
- /**
- * Constructor for expression before operator
- *
- * @param aExpr
- * expression
- * @param sOperator
- * operator
- */
- protected JOpUnary (@NonNull final IJExpression aExpr, @NonNull final String sOperator)
- {
- m_sOperator = ValueEnforcer.notNull (sOperator, "Operator");
- m_aExpr = ValueEnforcer.notNull (aExpr, "Expression");
- m_bOperatorComesFirst = false;
}
@NonNull
public String op ()
{
- return m_sOperator;
+ return m_aOperator.print;
}
@NonNull
@@ -101,15 +110,37 @@ public IJExpression expr ()
*/
public boolean opFirst ()
{
- return m_bOperatorComesFirst;
+ return m_aOperator.prefix;
}
public void generate (@NonNull final IJFormatter f)
{
- if (m_bOperatorComesFirst)
- f.print ('(').print (m_sOperator).generable (m_aExpr).print (')');
- else
- f.print ('(').generable (m_aExpr).print (m_sOperator).print (')');
+ boolean parentheses = true;
+ switch (f.settings ().parentheses.global)
+ {
+ case ALWAYS ->
+ {
+ parentheses = true;
+ }
+ case NOTOKEN ->
+ {
+ parentheses = m_aExpr.operatorPrecedence () != Precedence.TOKEN;
+ }
+ case REQUIRED ->
+ {
+ parentheses = m_aOperator.precedence.higherThan (m_aExpr.operatorPrecedence ());
+ }
+ default -> throw new IllegalArgumentException ("Unexpected value: " + f.settings ().parentheses.global);
+ }
+ if (m_aOperator.prefix)
+ f.print (m_aOperator.print);
+ if (parentheses)
+ f.print ('(');
+ f.generable (m_aExpr);
+ if (parentheses)
+ f.print (')');
+ if (!m_aOperator.prefix)
+ f.print (m_aOperator.print);
}
@Override
@@ -120,14 +151,18 @@ public boolean equals (final Object o)
if (o == null || getClass () != o.getClass ())
return false;
final JOpUnary rhs = (JOpUnary) o;
- return EqualsHelper.equals (m_sOperator, rhs.m_sOperator) &&
- EqualsHelper.equals (m_aExpr, rhs.m_aExpr) &&
- EqualsHelper.equals (m_bOperatorComesFirst, rhs.m_bOperatorComesFirst);
+ return EqualsHelper.equals (m_aOperator, rhs.m_aOperator) && EqualsHelper.equals (m_aExpr, rhs.m_aExpr);
}
@Override
public int hashCode ()
{
- return getHashCode (this, m_sOperator, m_aExpr, Boolean.valueOf (m_bOperatorComesFirst));
+ return getHashCode (this, m_aOperator, m_aExpr);
+ }
+
+ @Override
+ public Precedence operatorPrecedence ()
+ {
+ return m_aOperator.precedence;
}
}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/JOpUnaryTight.java b/jcodemodel/src/main/java/com/helger/jcodemodel/JOpUnaryTight.java
deleted file mode 100644
index 4732fb692..000000000
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/JOpUnaryTight.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
- * Portions Copyright 2013-2026 Philip Helger + contributors
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common Development
- * and Distribution License("CDDL") (collectively, the "License"). You
- * may not use this file except in compliance with the License. You can
- * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt. See the License for the specific
- * language governing permissions and limitations under the License.
- *
- * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
- *
- * GPL Classpath Exception:
- * Oracle designates this particular file as subject to the "Classpath"
- * exception as provided by Oracle in the GPL Version 2 section of the License
- * file that accompanied this code.
- *
- * Modifications:
- * If applicable, add the following below the License Header, with the fields
- * enclosed by brackets [] replaced by your own identifying information:
- * "Portions Copyright [year] [name of copyright owner]"
- *
- * Contributor(s):
- * If you wish your version of this file to be governed by only the CDDL or
- * only the GPL Version 2, indicate your decision by adding "[Contributor]
- * elects to include this software in this distribution under the [CDDL or GPL
- * Version 2] license." If you don't indicate a single choice of license, a
- * recipient has the option to distribute your version of this file under
- * either the CDDL, the GPL Version 2 or to extend the choice of license to
- * its licensees as provided above. However, if you add GPL Version 2 code
- * and therefore, elected the GPL Version 2 license, then the option applies
- * only if the new code is made subject to such option by the copyright
- * holder.
- */
-package com.helger.jcodemodel;
-
-import org.jspecify.annotations.NonNull;
-
-public class JOpUnaryTight extends JOpUnary
-{
- protected JOpUnaryTight (@NonNull final IJExpression aExpr, @NonNull final String sOperator)
- {
- super (aExpr, sOperator);
- }
-
- protected JOpUnaryTight (@NonNull final String sOperator, @NonNull final IJExpression aExpr)
- {
- super (sOperator, aExpr);
- }
-
- @Override
- public void generate (@NonNull final IJFormatter f)
- {
- if (opFirst ())
- f.print (op ()).generable (expr ());
- else
- f.generable (expr ()).print (op ());
- }
-}
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/writer/FormatterSettings.java b/jcodemodel/src/main/java/com/helger/jcodemodel/writer/FormatterSettings.java
index 0887fb4fe..ea00b5e03 100644
--- a/jcodemodel/src/main/java/com/helger/jcodemodel/writer/FormatterSettings.java
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/writer/FormatterSettings.java
@@ -43,6 +43,7 @@
import java.util.function.Consumer;
import com.helger.jcodemodel.writer.settings.Indent;
+import com.helger.jcodemodel.writer.settings.Parentheses;
import com.helger.jcodemodel.writer.settings.Wrap;
import com.helger.jcodemodel.writer.settings.Wrap.ListWrapping.EListWrapStrategy;
import com.helger.jcodemodel.writer.settings.Wrap.WordWrapping.EWordWrapStrategy;
@@ -87,6 +88,8 @@ public static FormatterSettings glelouet ()
public final Indent indent = new Indent ();
+ public final Parentheses parentheses = new Parentheses ();
+
public final Wrap wrap = new Wrap ();
public FormatterSettings configure (Consumer conf)
diff --git a/jcodemodel/src/main/java/com/helger/jcodemodel/writer/settings/Parentheses.java b/jcodemodel/src/main/java/com/helger/jcodemodel/writer/settings/Parentheses.java
new file mode 100644
index 000000000..4dff219bd
--- /dev/null
+++ b/jcodemodel/src/main/java/com/helger/jcodemodel/writer/settings/Parentheses.java
@@ -0,0 +1,23 @@
+package com.helger.jcodemodel.writer.settings;
+
+public class Parentheses
+{
+
+ /// examples are given for [ ( a + b ) * c ] + d
+ public static enum EParenthesesStrategy
+ {
+ // (((a)+(b))*(c))+(d)
+ ALWAYS,
+
+ // ((a+b)*c)+d
+ NOTOKEN,
+
+ // (a+b)*c+d
+ REQUIRED
+ }
+
+ /// default strategy for parenthesis. Expressions can use a more precise one but should fall back
+ /// to this when null.
+ public EParenthesesStrategy global = EParenthesesStrategy.REQUIRED;
+
+}
diff --git a/jcodemodel/src/test/java/com/helger/jcodemodel/JLambdaTest.java b/jcodemodel/src/test/java/com/helger/jcodemodel/JLambdaTest.java
index fb69e233e..781fcd148 100644
--- a/jcodemodel/src/test/java/com/helger/jcodemodel/JLambdaTest.java
+++ b/jcodemodel/src/test/java/com/helger/jcodemodel/JLambdaTest.java
@@ -65,7 +65,7 @@ public void testExpressionBasic ()
final JLambda aLambda = new JLambda ();
final JLambdaParam aParam = aLambda.addParam ("x");
aLambda.body ().lambdaExpr (aParam.mul (2));
- assertEquals ("x -> (x* 2)", CodeModelTestsHelper.toString (aLambda));
+ assertEquals ("x -> x* 2", CodeModelTestsHelper.toString (aLambda));
}
@Test
@@ -84,7 +84,7 @@ public void testExpressionBasicType ()
final JLambda aLambda = new JLambda ();
final JLambdaParam aParam = aLambda.addParam (cm.INT, "x");
aLambda.body ().lambdaExpr (aParam.mul (2));
- assertEquals ("(int x) -> (x* 2)", CodeModelTestsHelper.toString (aLambda));
+ assertEquals ("(int x) -> x* 2", CodeModelTestsHelper.toString (aLambda));
}
@Test
@@ -94,7 +94,7 @@ public void testExpressionBasic2 ()
final JLambdaParam aParam1 = aLambda.addParam ("x");
final JLambdaParam aParam2 = aLambda.addParam ("y");
aLambda.body ().lambdaExpr (aParam1.plus (aParam2));
- assertEquals ("(x, y) -> (x + y)", CodeModelTestsHelper.toString (aLambda));
+ assertEquals ("(x, y) -> x + y", CodeModelTestsHelper.toString (aLambda));
}
@Test
@@ -106,7 +106,7 @@ public void testExpressionBasicType2 ()
final JLambdaParam aParam1 = aLambda.addParam (cm.INT, "x");
final JLambdaParam aParam2 = aLambda.addParam (cm.BYTE, "y");
aLambda.body ().lambdaExpr (aParam1.plus (aParam2));
- assertEquals ("(int x, byte y) -> (x + y)", CodeModelTestsHelper.toString (aLambda));
+ assertEquals ("(int x, byte y) -> x + y", CodeModelTestsHelper.toString (aLambda));
}
@Test
@@ -117,7 +117,7 @@ public void testStatementBasicType ()
final JLambda aLambda = new JLambda ();
final JLambdaParam aParam = aLambda.addParam (cm.INT, "x");
aLambda.body ()._return (aParam.plus (1));
- assertEquals ("(int x) -> {" + CRLF + " return (x + 1);" + CRLF + "}" + CRLF,
+ assertEquals ("(int x) -> {" + CRLF + " return x + 1;" + CRLF + "}" + CRLF,
CodeModelTestsHelper.toString (aLambda));
}
diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesAlways.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesAlways.java
new file mode 100644
index 000000000..87b1dc33c
--- /dev/null
+++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesAlways.java
@@ -0,0 +1,71 @@
+/**
+ * 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.helger.jcodemodel.tests.format.parentheses;
+
+import javax.annotation.processing.Generated;
+
+@Generated("com.helger.jcodemodel.JCodeModel")
+public class OperatorParenthesesAlways {
+
+ /**
+ * test precedence of ternary operator and mathematical operations
+ */
+ public static int multIfSameOddityElseAdd(int a, int b) {
+ return (((a)%(2)) == ((b)%(2)))?((a)*(b)):((a)+(b));
+ }
+
+ /**
+ * test precedence of multiple ternary op
+ */
+ public static char representBools(boolean a, boolean b) {
+ return (a)?((b)?('3'):('2')):((b)?('1'):('0'));
+ }
+
+ /**
+ * test precedence of multiple ternary operations with other operations
+ */
+ public static String concat(String a, String b) {
+ return ((a) == (null))?(b):(((b) == (null))?(a):((a)+(b)));
+ }
+
+ /**
+ * test precedence of unary operations
+ */
+ public static int bitwiseImply(int a, int b) {
+ return (~(a))|(b);
+ }
+
+ /**
+ * test precedence of array component and ternary operator
+ */
+ public static int arrIdxCoalesce(int[] a, int[] b, int i) {
+ return ((((a) == (null))||((a.length)<= (i)))?(b):(a))[i];
+ }
+
+ /**
+ * test precedence of array component and comparison
+ */
+ public static boolean isSortedAsc(int[] arr) {
+ if (((arr) == (null))||((arr.length)<= (1))) {
+ return true;
+ }
+ for (int i = (arr.length)-(2); (i)>= (0); (i)--) {
+ if (((arr)[i])>((arr)[(i)+(1)])) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesNoToken.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesNoToken.java
new file mode 100644
index 000000000..912dcbe0f
--- /dev/null
+++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesNoToken.java
@@ -0,0 +1,71 @@
+/**
+ * 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.helger.jcodemodel.tests.format.parentheses;
+
+import javax.annotation.processing.Generated;
+
+@Generated("com.helger.jcodemodel.JCodeModel")
+public class OperatorParenthesesNoToken {
+
+ /**
+ * test precedence of ternary operator and mathematical operations
+ */
+ public static int multIfSameOddityElseAdd(int a, int b) {
+ return ((a% 2) == (b% 2))?(a*b):(a + b);
+ }
+
+ /**
+ * test precedence of multiple ternary op
+ */
+ public static char representBools(boolean a, boolean b) {
+ return a?(b?'3':'2'):(b?'1':'0');
+ }
+
+ /**
+ * test precedence of multiple ternary operations with other operations
+ */
+ public static String concat(String a, String b) {
+ return (a == null)?b:((b == null)?a:(a + b));
+ }
+
+ /**
+ * test precedence of unary operations
+ */
+ public static int bitwiseImply(int a, int b) {
+ return (~a)|b;
+ }
+
+ /**
+ * test precedence of array component and ternary operator
+ */
+ public static int arrIdxCoalesce(int[] a, int[] b, int i) {
+ return (((a == null)||(a.length<= i))?b:a)[i];
+ }
+
+ /**
+ * test precedence of array component and comparison
+ */
+ public static boolean isSortedAsc(int[] arr) {
+ if ((arr == null)||(arr.length<= 1)) {
+ return true;
+ }
+ for (int i = arr.length - 2; i >= 0; i --) {
+ if ((arr[i])>(arr[i + 1 ])) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesRequired.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesRequired.java
new file mode 100644
index 000000000..4302f68d6
--- /dev/null
+++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/format/parentheses/OperatorParenthesesRequired.java
@@ -0,0 +1,71 @@
+/**
+ * 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.helger.jcodemodel.tests.format.parentheses;
+
+import javax.annotation.processing.Generated;
+
+@Generated("com.helger.jcodemodel.JCodeModel")
+public class OperatorParenthesesRequired {
+
+ /**
+ * test precedence of ternary operator and mathematical operations
+ */
+ public static int multIfSameOddityElseAdd(int a, int b) {
+ return a% 2 == b% 2 ?a*b:a + b;
+ }
+
+ /**
+ * test precedence of multiple ternary op
+ */
+ public static char representBools(boolean a, boolean b) {
+ return a?(b?'3':'2'):(b?'1':'0');
+ }
+
+ /**
+ * test precedence of multiple ternary operations with other operations
+ */
+ public static String concat(String a, String b) {
+ return a == null?b:(b == null?a:a + b);
+ }
+
+ /**
+ * test precedence of unary operations
+ */
+ public static int bitwiseImply(int a, int b) {
+ return ~a|b;
+ }
+
+ /**
+ * test precedence of array component and ternary operator
+ */
+ public static int arrIdxCoalesce(int[] a, int[] b, int i) {
+ return (a == null||a.length<= i?b:a)[i];
+ }
+
+ /**
+ * test precedence of array component and comparison
+ */
+ public static boolean isSortedAsc(int[] arr) {
+ if (arr == null||arr.length<= 1) {
+ return true;
+ }
+ for (int i = arr.length - 2; i >= 0; i --) {
+ if (arr[i]>arr[i + 1 ]) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/instanceofvar/ExampleInstanceOfVar.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/instanceofvar/ExampleInstanceOfVar.java
index 2cc74e3f1..67212364f 100644
--- a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/instanceofvar/ExampleInstanceOfVar.java
+++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/instanceofvar/ExampleInstanceOfVar.java
@@ -25,7 +25,7 @@ public static int toInt(Object o) {
if (o == null) {
return 0;
}
- if ((o instanceof String s)&&(!s.isBlank())) {
+ if ((o instanceof String s)&&!s.isBlank()) {
return s.strip().length();
}
if ((o instanceof Collection c)) {
diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/lazy/GeneratedLazyClass.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/lazy/GeneratedLazyClass.java
index db466209c..5ed7efe26 100644
--- a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/lazy/GeneratedLazyClass.java
+++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/lazy/GeneratedLazyClass.java
@@ -20,7 +20,7 @@
public class GeneratedLazyClass {
public int sum() {
- return (((getSyncInstance()+ getSyncStatic())+ getASyncInstance())+ getASyncStatic());
+ return getSyncInstance()+ getSyncStatic()+ getASyncInstance()+ getASyncStatic();
}
private volatile Integer syncInstance;
diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointDistance.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointDistance.java
index 112356f45..ee7c23154 100644
--- a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointDistance.java
+++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointDistance.java
@@ -20,6 +20,6 @@
public record PointDistance(int x, int y) {
public double distance() {
- return Math.sqrt(((x*x)+(y*y)));
+ return Math.sqrt(x*x + y*y);
}
}
diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/switchexpression/BasicSwitch.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/switchexpression/BasicSwitch.java
index 2826384aa..2780f8b43 100644
--- a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/switchexpression/BasicSwitch.java
+++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/switchexpression/BasicSwitch.java
@@ -26,9 +26,9 @@ public static boolean isOdd(int i) {
case 1, 3 ->
true;
case 4, 5, 6, 7, 8, 9 ->
- isOdd((i - 2));
+ isOdd(i - 2);
default -> {
- throw new UnsupportedOperationException(("case not handled : "+ i));
+ throw new UnsupportedOperationException("case not handled : "+ i);
}
}
;
diff --git a/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/format/parentheses/OperatorTestGen.java b/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/format/parentheses/OperatorTestGen.java
new file mode 100644
index 000000000..23c97d0d6
--- /dev/null
+++ b/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/format/parentheses/OperatorTestGen.java
@@ -0,0 +1,116 @@
+package com.helger.jcodemodel.tests.format.parentheses;
+
+import com.helger.jcodemodel.JDefinedClass;
+import com.helger.jcodemodel.JExpr;
+import com.helger.jcodemodel.JForLoop;
+import com.helger.jcodemodel.JMethod;
+import com.helger.jcodemodel.JMod;
+import com.helger.jcodemodel.JOp;
+import com.helger.jcodemodel.JPackage;
+import com.helger.jcodemodel.JVar;
+import com.helger.jcodemodel.compile.annotation.TestJCM;
+import com.helger.jcodemodel.exceptions.JCodeModelException;
+import com.helger.jcodemodel.vars.JBlockVar;
+import com.helger.jcodemodel.writer.FormatterSettings;
+import com.helger.jcodemodel.writer.settings.Parentheses.EParenthesesStrategy;
+
+@TestJCM
+public class OperatorTestGen {
+
+ protected static void addMethods(JDefinedClass clazz) {
+ {
+ JMethod meth =
+ clazz.method(JMod.PUBLIC | JMod.STATIC, clazz.owner().INT, "multIfSameOddityElseAdd");
+ meth.javadoc().add("test precedence of ternary operator and mathematical operations");
+ JVar a = meth.param(clazz.owner().INT, "a");
+ JVar b = meth.param(clazz.owner().INT, "b");
+ meth.body()._return(
+ JExpr.cond(
+ JOp.mod(a, JExpr.lit(2)).eq(JOp.mod(b, JExpr.lit(2))),
+ JOp.mul(a, b),
+ JOp.plus(a, b)));
+ }
+ {
+ JMethod meth =
+ clazz.method(JMod.PUBLIC | JMod.STATIC, clazz.owner().CHAR, "representBools");
+ meth.javadoc().add("test precedence of multiple ternary op");
+ JVar a = meth.param(clazz.owner().BOOLEAN, "a");
+ JVar b = meth.param(clazz.owner().BOOLEAN, "b");
+ meth.body()._return(
+ JExpr.cond(
+ a,
+ JExpr.cond(b, JExpr.lit('3'), JExpr.lit('2')),
+ JExpr.cond(b, JExpr.lit('1'), JExpr.lit('0'))));
+ }
+ {
+ JMethod meth =
+ clazz.method(JMod.PUBLIC | JMod.STATIC, clazz.owner().ref(String.class), "concat");
+ meth.javadoc().add("test precedence of multiple ternary operations with other operations");
+ JVar a = meth.param(clazz.owner().ref(String.class), "a");
+ JVar b = meth.param(clazz.owner().ref(String.class), "b");
+ meth.body()._return(
+ JExpr.cond(
+ a.eqNull(),
+ b,
+ JExpr.cond(b.eqNull(), a, a.plus(b))));
+ }
+ {
+ JMethod meth =
+ clazz.method(JMod.PUBLIC | JMod.STATIC, clazz.owner().INT, "bitwiseImply");
+ meth.javadoc().add("test precedence of unary operations");
+ JVar a = meth.param(clazz.owner().INT, "a");
+ JVar b = meth.param(clazz.owner().INT, "b");
+ meth.body()._return(
+ a.complement().bor(b));
+ }
+ {
+ JMethod meth =
+ clazz.method(JMod.PUBLIC | JMod.STATIC, clazz.owner().INT, "arrIdxCoalesce");
+ meth.javadoc().add("test precedence of array component and ternary operator");
+ JVar a = meth.param(clazz.owner().INT.array(), "a");
+ JVar b = meth.param(clazz.owner().INT.array(), "b");
+ JVar i = meth.param(clazz.owner().INT, "i");
+ meth.body()._return(JExpr.cond(
+ a.eqNull().cor(a.ref("length").lte(i)),
+ b,
+ a)
+ .component(i));
+ }
+ {
+ JMethod meth =
+ clazz.method (JMod.PUBLIC | JMod.STATIC, clazz.owner ().BOOLEAN, "isSortedAsc");
+ meth.javadoc().add("test precedence of array component and comparison");
+ JVar arr = meth.param(clazz.owner().INT.array(), "arr");
+ // if(arr==null || arr.length==0) return true;
+ meth.body ()._if (arr.eqNull ().cor (arr.ref ("length").lte (JExpr.lit (1))))._then ()._return (JExpr.TRUE);
+ // for(int i = arr.length-2; i>= 0 ; i--)
+ JForLoop _for = meth.body ()._for ();
+ JBlockVar i = _for.init (clazz.owner ().INT, "i", arr.ref ("length").minus (2));
+ _for.test (i.gte (0));
+ _for.update (i.decr ());
+ // if(arr[i]>arr[i+1) return false;
+ _for.body ()._if (arr.component (i).gt (arr.component (i.plus (1))))._then ()._return (JExpr.FALSE);
+ meth.body()._return(JExpr.TRUE);
+ }
+ }
+
+ protected static void addClassMethod(JPackage root, String className) throws JCodeModelException {
+ addMethods(root._class(className));
+ }
+
+ public void testWithParenthesesAlways(final JPackage root, FormatterSettings settings) throws JCodeModelException {
+ settings.parentheses.global = EParenthesesStrategy.ALWAYS;
+ addClassMethod(root, "OperatorParenthesesAlways");
+ }
+
+ public void testWithParenthesesNoToken(final JPackage root, FormatterSettings settings) throws JCodeModelException {
+ settings.parentheses.global = EParenthesesStrategy.NOTOKEN;
+ addClassMethod(root, "OperatorParenthesesNoToken");
+ }
+
+ public void testWithParenthesesRequired(final JPackage root, FormatterSettings settings) throws JCodeModelException {
+ settings.parentheses.global = EParenthesesStrategy.REQUIRED;
+ addClassMethod(root, "OperatorParenthesesRequired");
+ }
+
+}
diff --git a/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/format/parentheses/OperatorTest.java b/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/format/parentheses/OperatorTest.java
new file mode 100644
index 000000000..7ab92f4b9
--- /dev/null
+++ b/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/format/parentheses/OperatorTest.java
@@ -0,0 +1,104 @@
+package com.helger.jcodemodel.tests.format.parentheses;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/// results should be the same for each implementation
+public class OperatorTest {
+
+ @FunctionalInterface
+ interface IF1 {
+ int multIfSameOddityElseAdd(int a, int b);
+ }
+
+ @Test
+ public void testMultIfSameOddityElseAdd() {
+ for (IF1 f : new IF1[] {
+ OperatorParenthesesAlways::multIfSameOddityElseAdd,
+ OperatorParenthesesNoToken::multIfSameOddityElseAdd,
+ OperatorParenthesesRequired::multIfSameOddityElseAdd
+ }) {
+ Assert.assertEquals(1, f.multIfSameOddityElseAdd(1, 1));
+ Assert.assertEquals(4, f.multIfSameOddityElseAdd(2, 2));
+ Assert.assertEquals(5, f.multIfSameOddityElseAdd(2, 3));
+ Assert.assertEquals(8, f.multIfSameOddityElseAdd(2, 4));
+ Assert.assertEquals(7, f.multIfSameOddityElseAdd(2, 5));
+ }
+ }
+
+ @FunctionalInterface
+ interface IF2 {
+ char representBools(boolean a, boolean b);
+ }
+
+ @Test
+ public void testRepresentBools() {
+ for (IF2 f : new IF2[] {
+ OperatorParenthesesAlways::representBools,
+ OperatorParenthesesNoToken::representBools,
+ OperatorParenthesesRequired::representBools
+ }) {
+ Assert.assertEquals('0', f.representBools(false, false));
+ Assert.assertEquals('1', f.representBools(false, true));
+ Assert.assertEquals('2', f.representBools(true, false));
+ Assert.assertEquals('3', f.representBools(true, true));
+ }
+ }
+
+ @FunctionalInterface
+ interface IF3 {
+ String concat(String a, String b);
+ }
+
+ @Test
+ public void testConcat() {
+ for (IF3 f : new IF3[] {
+ OperatorParenthesesAlways::concat,
+ OperatorParenthesesNoToken::concat,
+ OperatorParenthesesRequired::concat
+ }) {
+ Assert.assertEquals(null, f.concat(null, null));
+ Assert.assertEquals("a", f.concat("a", null));
+ Assert.assertEquals("b", f.concat(null, "b"));
+ Assert.assertEquals("ab", f.concat("a", "b"));
+ }
+ }
+
+ @FunctionalInterface
+ interface IF4 {
+ int bitwiseImply(int a, int b);
+ }
+
+ @Test
+ public void testBitwiseImply() {
+ for (IF4 f : new IF4[] {
+ OperatorParenthesesAlways::bitwiseImply,
+ OperatorParenthesesNoToken::bitwiseImply,
+ OperatorParenthesesRequired::bitwiseImply
+ }) {
+ Assert.assertEquals(0xffffffff, f.bitwiseImply(0, 1));
+ }
+ }
+
+ @FunctionalInterface
+ interface IF5
+ {
+ boolean isSortedAsc (int [] arr);
+ }
+
+ @Test
+ public void testIsSortedAsc ()
+ {
+ for (IF5 f : new IF5 [] { OperatorParenthesesAlways::isSortedAsc,
+ OperatorParenthesesNoToken::isSortedAsc,
+ OperatorParenthesesRequired::isSortedAsc })
+ {
+ Assert.assertTrue (f.isSortedAsc (null));
+ Assert.assertTrue (f.isSortedAsc (new int [] { 0 }));
+ Assert.assertTrue (f.isSortedAsc (new int [] { 0, 1 }));
+ Assert.assertTrue (f.isSortedAsc (new int [] { 0, 1, 2, 3, 4 }));
+ Assert.assertFalse (f.isSortedAsc (new int [] { 0, 1, 3, 2, 4 }));
+ }
+ }
+
+}