21
21
22
22
package com .igormaznitsa .jcp .expression ;
23
23
24
+ import static com .igormaznitsa .jcp .expression .functions .AbstractFunction .ARITY_0 ;
25
+
24
26
import com .igormaznitsa .jcp .exceptions .FilePositionInfo ;
25
27
import com .igormaznitsa .jcp .exceptions .PreprocessorException ;
26
28
import com .igormaznitsa .jcp .expression .functions .AbstractFunction ;
40
42
public class ExpressionTreeElement {
41
43
42
44
public static final ExpressionTreeElement EMPTY_SLOT = new ExpressionTreeElement ();
45
+
43
46
/**
44
47
* Inside constant to be used for speed up some operations
45
48
*/
@@ -48,6 +51,8 @@ public class ExpressionTreeElement {
48
51
* Empty array to avoid unnecessary operations
49
52
*/
50
53
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 ;
51
56
/**
52
57
* Contains the source string for the expression.
53
58
*/
@@ -63,7 +68,7 @@ public class ExpressionTreeElement {
63
68
/**
64
69
* The array contains links to the tree element children
65
70
*/
66
- private ExpressionTreeElement [] childElements ;
71
+ private ExpressionTreeElement [] childrenSlots ;
67
72
/**
68
73
* The link to the parent element, if it is the tree root then it contains null
69
74
*/
@@ -75,21 +80,18 @@ public class ExpressionTreeElement {
75
80
/**
76
81
* Because I fill children sequentially, the variable contains the index of the first empty child slot
77
82
*/
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 ;
86
84
/**
87
85
* Set of allowed arities.
88
86
*
89
87
* @since 7.3.0
90
88
*/
91
- private Set <Integer > allowedArities = Set .of ();
89
+ private Set <Integer > expectedArities = Set .of ();
92
90
91
+ private ExpressionTreeElement () {
92
+ this .sourceString = "" ;
93
+ this .includeStack = new FilePositionInfo [0 ];
94
+ }
93
95
/**
94
96
* The constructor
95
97
*
@@ -107,22 +109,23 @@ private ExpressionTreeElement() {
107
109
this .includeStack , null );
108
110
}
109
111
110
- final int arity ;
111
112
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 ];
114
116
} else if (item .getExpressionItemType () == ExpressionItemType .FUNCTION ) {
115
117
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 ];
118
122
} else {
119
- arity = 0 ;
120
- this .allowedArities = ZERO_ARITY ;
123
+ this . expectedArities = ARITY_0 ;
124
+ this .childrenSlots = EMPTY ;
121
125
}
122
- priority = item .getExpressionItemPriority ().getPriority ();
126
+ this . priority = item .getExpressionItemPriority ().getPriority ();
123
127
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 );
126
129
}
127
130
128
131
/**
@@ -132,18 +135,18 @@ private ExpressionTreeElement() {
132
135
* @since 7.3.0
133
136
*/
134
137
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 )
136
139
.collect (Collectors .toUnmodifiableList ());
137
140
}
138
141
139
142
/**
140
143
* Variants of allowed arities by the expression tree element
141
144
*
142
- * @return allowed artiy numbers as set
145
+ * @return set contains number of expected arities
143
146
* @since 7.3.0
144
147
*/
145
- public Set <Integer > getAllowedArities () {
146
- return this .allowedArities ;
148
+ public Set <Integer > getExpectedArities () {
149
+ return this .expectedArities ;
147
150
}
148
151
149
152
/**
@@ -178,15 +181,6 @@ public ExpressionItem getItem() {
178
181
return this .savedItem ;
179
182
}
180
183
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
-
190
184
/**
191
185
* Get the parent for the element
192
186
*
@@ -247,7 +241,7 @@ public boolean replaceElement(final ExpressionTreeElement oldOne,
247
241
248
242
boolean result = false ;
249
243
250
- final ExpressionTreeElement [] children = childElements ;
244
+ final ExpressionTreeElement [] children = childrenSlots ;
251
245
final int len = children .length ;
252
246
253
247
for (int i = 0 ; i < len ; i ++) {
@@ -272,7 +266,7 @@ public boolean replaceElement(final ExpressionTreeElement oldOne,
272
266
273
267
public ExpressionTreeElement getChildForIndex (final int index ) {
274
268
assertNotEmptySlot ();
275
- return this .childElements [index ];
269
+ return this .childrenSlots [index ];
276
270
}
277
271
278
272
/**
@@ -287,11 +281,8 @@ public ExpressionTreeElement addTreeElement(final ExpressionTreeElement element)
287
281
Objects .requireNonNull (element , "The element is null" );
288
282
289
283
final int newElementPriority = element .getPriority ();
290
-
291
284
ExpressionTreeElement result = this ;
292
-
293
285
final ExpressionTreeElement parentTreeElement = this .parentTreeElement ;
294
-
295
286
final int currentPriority = getPriority ();
296
287
297
288
if (newElementPriority < currentPriority ) {
@@ -305,22 +296,21 @@ public ExpressionTreeElement addTreeElement(final ExpressionTreeElement element)
305
296
if (parentTreeElement != null ) {
306
297
parentTreeElement .replaceElement (this , element );
307
298
}
308
- if (element .nextChildSlot >= element .childElements .length ) {
299
+ if (element .nextChildSlotIndex >= element .childrenSlots .length ) {
309
300
throw new PreprocessorException (
310
301
"[Expression]Can't process expression item, may be wrong number of arguments" ,
311
302
this .sourceString , this .includeStack , null );
312
303
}
313
- element .childElements [element .nextChildSlot ] = this ;
314
- element .nextChildSlot ++;
304
+ element .childrenSlots [element .nextChildSlotIndex ] = this ;
305
+ element .nextChildSlotIndex ++;
315
306
this .parentTreeElement = element ;
316
307
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 ];
321
311
if (lastElement .getPriority () > newElementPriority ) {
322
312
element .addElementToNextFreeSlot (lastElement );
323
- childElements [lastElementIndex ] = element ;
313
+ this . childrenSlots [lastElementIndex ] = element ;
324
314
element .parentTreeElement = this ;
325
315
result = element ;
326
316
}
@@ -338,7 +328,7 @@ public ExpressionTreeElement addTreeElement(final ExpressionTreeElement element)
338
328
* @return true if there is not any free child slot else false
339
329
*/
340
330
public boolean isFull () {
341
- return nextChildSlot >= childElements .length ;
331
+ return this . nextChildSlotIndex >= this . childrenSlots .length ;
342
332
}
343
333
344
334
/**
@@ -354,7 +344,7 @@ public void fillArguments(final List<ExpressionTree> arguments) {
354
344
this .includeStack , null );
355
345
}
356
346
357
- if (childElements .length != arguments .size ()) {
347
+ if (childrenSlots .length != arguments .size ()) {
358
348
throw new PreprocessorException ("Wrong argument list size" , this .sourceString ,
359
349
this .includeStack , null );
360
350
}
@@ -366,7 +356,7 @@ public void fillArguments(final List<ExpressionTree> arguments) {
366
356
this .sourceString , this .includeStack , null );
367
357
}
368
358
369
- if (!childElements [i ].isEmptySlot ()) {
359
+ if (!childrenSlots [i ].isEmptySlot ()) {
370
360
throw new PreprocessorException (
371
361
"[Expression]Non-empty slot detected, it is possible that there is a program error, contact a developer please" ,
372
362
this .sourceString , this .includeStack , null );
@@ -377,7 +367,7 @@ public void fillArguments(final List<ExpressionTree> arguments) {
377
367
throw new PreprocessorException ("[Expression]Empty argument [" + (i + 1 ) + "] detected" ,
378
368
this .sourceString , this .includeStack , null );
379
369
}
380
- childElements [i ] = root ;
370
+ childrenSlots [i ] = root ;
381
371
root .parentTreeElement = this ;
382
372
383
373
i ++;
@@ -395,7 +385,7 @@ private void addElementToNextFreeSlot(final ExpressionTreeElement element) {
395
385
this .includeStack , null );
396
386
}
397
387
398
- if (childElements .length == 0 ) {
388
+ if (childrenSlots .length == 0 ) {
399
389
throw new PreprocessorException (
400
390
"[Expression]Unexpected element, may be unknown function [" + savedItem .toString () + ']' ,
401
391
this .sourceString , this .includeStack , null );
@@ -404,7 +394,7 @@ private void addElementToNextFreeSlot(final ExpressionTreeElement element) {
404
394
"[Expression]There is not any possibility to add new argument [" + savedItem .toString () +
405
395
']' , this .sourceString , this .includeStack , null );
406
396
} else {
407
- childElements [ nextChildSlot ++] = element ;
397
+ childrenSlots [ nextChildSlotIndex ++] = element ;
408
398
}
409
399
element .parentTreeElement = this ;
410
400
}
@@ -418,20 +408,20 @@ public void postProcess() {
418
408
switch (savedItem .getExpressionItemType ()) {
419
409
case OPERATOR : {
420
410
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 ];
423
413
final ExpressionItem item = left .getItem ();
424
414
if (item .getExpressionItemType () == ExpressionItemType .VALUE ) {
425
415
final Value val = (Value ) item ;
426
416
switch (val .getType ()) {
427
417
case INT : {
428
- childElements = EMPTY ;
418
+ childrenSlots = EMPTY ;
429
419
savedItem = Value .valueOf (-val .asLong ());
430
420
makeMaxPriority ();
431
421
}
432
422
break ;
433
423
case FLOAT : {
434
- childElements = EMPTY ;
424
+ childrenSlots = EMPTY ;
435
425
savedItem = Value .valueOf (0.0f - val .asFloat ());
436
426
makeMaxPriority ();
437
427
}
@@ -445,14 +435,14 @@ public void postProcess() {
445
435
}
446
436
}
447
437
} else {
448
- for (final ExpressionTreeElement element : childElements ) {
438
+ for (final ExpressionTreeElement element : childrenSlots ) {
449
439
if (!element .isEmptySlot ()) {
450
440
element .postProcess ();
451
441
}
452
442
}
453
443
}
454
444
} else {
455
- for (final ExpressionTreeElement element : childElements ) {
445
+ for (final ExpressionTreeElement element : childrenSlots ) {
456
446
if (!element .isEmptySlot ()) {
457
447
element .postProcess ();
458
448
}
@@ -461,7 +451,7 @@ public void postProcess() {
461
451
}
462
452
break ;
463
453
case FUNCTION : {
464
- for (final ExpressionTreeElement element : childElements ) {
454
+ for (final ExpressionTreeElement element : childrenSlots ) {
465
455
if (!element .isEmptySlot ()) {
466
456
element .postProcess ();
467
457
}
0 commit comments