2121
2222package com .igormaznitsa .jcp .expression ;
2323
24+ import static com .igormaznitsa .jcp .expression .functions .AbstractFunction .ARITY_0 ;
25+
2426import com .igormaznitsa .jcp .exceptions .FilePositionInfo ;
2527import com .igormaznitsa .jcp .exceptions .PreprocessorException ;
2628import com .igormaznitsa .jcp .expression .functions .AbstractFunction ;
4042public class ExpressionTreeElement {
4143
4244 public static final ExpressionTreeElement EMPTY_SLOT = new ExpressionTreeElement ();
45+
4346 /**
4447 * Inside constant to be used for speed up some operations
4548 */
@@ -48,6 +51,8 @@ public class ExpressionTreeElement {
4851 * Empty array to avoid unnecessary operations
4952 */
5053 private static final ExpressionTreeElement [] EMPTY = new ExpressionTreeElement [0 ];
54+ public static final int ANY_ARITY = -1 ;
55+ private static final int MAX_FUNCTION_ARGUMENTS = 256 ;
5156 /**
5257 * Contains the source string for the expression.
5358 */
@@ -63,7 +68,7 @@ public class ExpressionTreeElement {
6368 /**
6469 * The array contains links to the tree element children
6570 */
66- private ExpressionTreeElement [] childElements ;
71+ private ExpressionTreeElement [] childrenSlots ;
6772 /**
6873 * The link to the parent element, if it is the tree root then it contains null
6974 */
@@ -75,21 +80,18 @@ public class ExpressionTreeElement {
7580 /**
7681 * Because I fill children sequentially, the variable contains the index of the first empty child slot
7782 */
78- private int nextChildSlot = 0 ;
79-
80- private static final Set <Integer > ZERO_ARITY = Set .of (0 );
81-
82- private ExpressionTreeElement () {
83- this .sourceString = "" ;
84- this .includeStack = new FilePositionInfo [0 ];
85- }
83+ private int nextChildSlotIndex = 0 ;
8684 /**
8785 * Set of allowed arities.
8886 *
8987 * @since 7.3.0
9088 */
91- private Set <Integer > allowedArities = Set .of ();
89+ private Set <Integer > expectedArities = Set .of ();
9290
91+ private ExpressionTreeElement () {
92+ this .sourceString = "" ;
93+ this .includeStack = new FilePositionInfo [0 ];
94+ }
9395 /**
9496 * The constructor
9597 *
@@ -107,22 +109,23 @@ private ExpressionTreeElement() {
107109 this .includeStack , null );
108110 }
109111
110- final int arity ;
111112 if (item .getExpressionItemType () == ExpressionItemType .OPERATOR ) {
112- arity = ((AbstractOperator ) item ).getArity ();
113- this .allowedArities = Set .of (arity );
113+ final int arity = ((AbstractOperator ) item ).getArity ();
114+ this .expectedArities = Set .of (arity );
115+ this .childrenSlots = new ExpressionTreeElement [arity ];
114116 } else if (item .getExpressionItemType () == ExpressionItemType .FUNCTION ) {
115117 final AbstractFunction functionItem = (AbstractFunction ) item ;
116- this .allowedArities = functionItem .getArity ();
117- arity = this .allowedArities .stream ().mapToInt (x -> x ).max ().orElse (0 );
118+ this .expectedArities = functionItem .getArity ();
119+ final int arity = this .expectedArities .stream ().mapToInt (x -> x ).max ().orElse (0 );
120+ this .childrenSlots = this .expectedArities .contains (ANY_ARITY ) ?
121+ new ExpressionTreeElement [MAX_FUNCTION_ARGUMENTS ] : new ExpressionTreeElement [arity ];
118122 } else {
119- arity = 0 ;
120- this .allowedArities = ZERO_ARITY ;
123+ this . expectedArities = ARITY_0 ;
124+ this .childrenSlots = EMPTY ;
121125 }
122- priority = item .getExpressionItemPriority ().getPriority ();
126+ this . priority = item .getExpressionItemPriority ().getPriority ();
123127 this .savedItem = item ;
124- childElements = arity == 0 ? EMPTY : new ExpressionTreeElement [arity ];
125- Arrays .fill (this .childElements , EMPTY_SLOT );
128+ Arrays .fill (this .childrenSlots , EMPTY_SLOT );
126129 }
127130
128131 /**
@@ -132,18 +135,18 @@ private ExpressionTreeElement() {
132135 * @since 7.3.0
133136 */
134137 public List <ExpressionTreeElement > extractEffectiveChildren () {
135- return Arrays .stream (this .childElements ).takeWhile (x -> x != EMPTY_SLOT )
138+ return Arrays .stream (this .childrenSlots ).takeWhile (x -> x != EMPTY_SLOT )
136139 .collect (Collectors .toUnmodifiableList ());
137140 }
138141
139142 /**
140143 * Variants of allowed arities by the expression tree element
141144 *
142- * @return allowed artiy numbers as set
145+ * @return set contains number of expected arities
143146 * @since 7.3.0
144147 */
145- public Set <Integer > getAllowedArities () {
146- return this .allowedArities ;
148+ public Set <Integer > getExpectedArities () {
149+ return this .expectedArities ;
147150 }
148151
149152 /**
@@ -178,15 +181,6 @@ public ExpressionItem getItem() {
178181 return this .savedItem ;
179182 }
180183
181- /**
182- * Get arity for the element (I mean possible children number)
183- *
184- * @return the arity, zero for elements without children
185- */
186- public int getArity () {
187- return childElements .length ;
188- }
189-
190184 /**
191185 * Get the parent for the element
192186 *
@@ -247,7 +241,7 @@ public boolean replaceElement(final ExpressionTreeElement oldOne,
247241
248242 boolean result = false ;
249243
250- final ExpressionTreeElement [] children = childElements ;
244+ final ExpressionTreeElement [] children = childrenSlots ;
251245 final int len = children .length ;
252246
253247 for (int i = 0 ; i < len ; i ++) {
@@ -272,7 +266,7 @@ public boolean replaceElement(final ExpressionTreeElement oldOne,
272266
273267 public ExpressionTreeElement getChildForIndex (final int index ) {
274268 assertNotEmptySlot ();
275- return this .childElements [index ];
269+ return this .childrenSlots [index ];
276270 }
277271
278272 /**
@@ -287,11 +281,8 @@ public ExpressionTreeElement addTreeElement(final ExpressionTreeElement element)
287281 Objects .requireNonNull (element , "The element is null" );
288282
289283 final int newElementPriority = element .getPriority ();
290-
291284 ExpressionTreeElement result = this ;
292-
293285 final ExpressionTreeElement parentTreeElement = this .parentTreeElement ;
294-
295286 final int currentPriority = getPriority ();
296287
297288 if (newElementPriority < currentPriority ) {
@@ -305,22 +296,21 @@ public ExpressionTreeElement addTreeElement(final ExpressionTreeElement element)
305296 if (parentTreeElement != null ) {
306297 parentTreeElement .replaceElement (this , element );
307298 }
308- if (element .nextChildSlot >= element .childElements .length ) {
299+ if (element .nextChildSlotIndex >= element .childrenSlots .length ) {
309300 throw new PreprocessorException (
310301 "[Expression]Can't process expression item, may be wrong number of arguments" ,
311302 this .sourceString , this .includeStack , null );
312303 }
313- element .childElements [element .nextChildSlot ] = this ;
314- element .nextChildSlot ++;
304+ element .childrenSlots [element .nextChildSlotIndex ] = this ;
305+ element .nextChildSlotIndex ++;
315306 this .parentTreeElement = element ;
316307 result = element ;
317- } else if (isFull ()) {
318- final int lastElementIndex = getArity () - 1 ;
319-
320- final ExpressionTreeElement lastElement = childElements [lastElementIndex ];
308+ } else if (this .isFull ()) {
309+ final int lastElementIndex = this .nextChildSlotIndex - 1 ;
310+ final ExpressionTreeElement lastElement = this .childrenSlots [lastElementIndex ];
321311 if (lastElement .getPriority () > newElementPriority ) {
322312 element .addElementToNextFreeSlot (lastElement );
323- childElements [lastElementIndex ] = element ;
313+ this . childrenSlots [lastElementIndex ] = element ;
324314 element .parentTreeElement = this ;
325315 result = element ;
326316 }
@@ -338,7 +328,7 @@ public ExpressionTreeElement addTreeElement(final ExpressionTreeElement element)
338328 * @return true if there is not any free child slot else false
339329 */
340330 public boolean isFull () {
341- return nextChildSlot >= childElements .length ;
331+ return this . nextChildSlotIndex >= this . childrenSlots .length ;
342332 }
343333
344334 /**
@@ -354,7 +344,7 @@ public void fillArguments(final List<ExpressionTree> arguments) {
354344 this .includeStack , null );
355345 }
356346
357- if (childElements .length != arguments .size ()) {
347+ if (childrenSlots .length != arguments .size ()) {
358348 throw new PreprocessorException ("Wrong argument list size" , this .sourceString ,
359349 this .includeStack , null );
360350 }
@@ -366,7 +356,7 @@ public void fillArguments(final List<ExpressionTree> arguments) {
366356 this .sourceString , this .includeStack , null );
367357 }
368358
369- if (!childElements [i ].isEmptySlot ()) {
359+ if (!childrenSlots [i ].isEmptySlot ()) {
370360 throw new PreprocessorException (
371361 "[Expression]Non-empty slot detected, it is possible that there is a program error, contact a developer please" ,
372362 this .sourceString , this .includeStack , null );
@@ -377,7 +367,7 @@ public void fillArguments(final List<ExpressionTree> arguments) {
377367 throw new PreprocessorException ("[Expression]Empty argument [" + (i + 1 ) + "] detected" ,
378368 this .sourceString , this .includeStack , null );
379369 }
380- childElements [i ] = root ;
370+ childrenSlots [i ] = root ;
381371 root .parentTreeElement = this ;
382372
383373 i ++;
@@ -395,7 +385,7 @@ private void addElementToNextFreeSlot(final ExpressionTreeElement element) {
395385 this .includeStack , null );
396386 }
397387
398- if (childElements .length == 0 ) {
388+ if (childrenSlots .length == 0 ) {
399389 throw new PreprocessorException (
400390 "[Expression]Unexpected element, may be unknown function [" + savedItem .toString () + ']' ,
401391 this .sourceString , this .includeStack , null );
@@ -404,7 +394,7 @@ private void addElementToNextFreeSlot(final ExpressionTreeElement element) {
404394 "[Expression]There is not any possibility to add new argument [" + savedItem .toString () +
405395 ']' , this .sourceString , this .includeStack , null );
406396 } else {
407- childElements [ nextChildSlot ++] = element ;
397+ childrenSlots [ nextChildSlotIndex ++] = element ;
408398 }
409399 element .parentTreeElement = this ;
410400 }
@@ -418,20 +408,20 @@ public void postProcess() {
418408 switch (savedItem .getExpressionItemType ()) {
419409 case OPERATOR : {
420410 if (savedItem == OPERATOR_SUB ) {
421- if (!childElements [0 ].isEmptySlot () && childElements [1 ].isEmptySlot ()) {
422- final ExpressionTreeElement left = childElements [0 ];
411+ if (!childrenSlots [0 ].isEmptySlot () && childrenSlots [1 ].isEmptySlot ()) {
412+ final ExpressionTreeElement left = childrenSlots [0 ];
423413 final ExpressionItem item = left .getItem ();
424414 if (item .getExpressionItemType () == ExpressionItemType .VALUE ) {
425415 final Value val = (Value ) item ;
426416 switch (val .getType ()) {
427417 case INT : {
428- childElements = EMPTY ;
418+ childrenSlots = EMPTY ;
429419 savedItem = Value .valueOf (-val .asLong ());
430420 makeMaxPriority ();
431421 }
432422 break ;
433423 case FLOAT : {
434- childElements = EMPTY ;
424+ childrenSlots = EMPTY ;
435425 savedItem = Value .valueOf (0.0f - val .asFloat ());
436426 makeMaxPriority ();
437427 }
@@ -445,14 +435,14 @@ public void postProcess() {
445435 }
446436 }
447437 } else {
448- for (final ExpressionTreeElement element : childElements ) {
438+ for (final ExpressionTreeElement element : childrenSlots ) {
449439 if (!element .isEmptySlot ()) {
450440 element .postProcess ();
451441 }
452442 }
453443 }
454444 } else {
455- for (final ExpressionTreeElement element : childElements ) {
445+ for (final ExpressionTreeElement element : childrenSlots ) {
456446 if (!element .isEmptySlot ()) {
457447 element .postProcess ();
458448 }
@@ -461,7 +451,7 @@ public void postProcess() {
461451 }
462452 break ;
463453 case FUNCTION : {
464- for (final ExpressionTreeElement element : childElements ) {
454+ for (final ExpressionTreeElement element : childrenSlots ) {
465455 if (!element .isEmptySlot ()) {
466456 element .postProcess ();
467457 }
0 commit comments