1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jxpath.ri.compiler;
19
20 import java.text.DecimalFormat;
21 import java.text.DecimalFormatSymbols;
22 import java.text.NumberFormat;
23 import java.util.Collection;
24 import java.util.Locale;
25
26 import org.apache.commons.jxpath.BasicNodeSet;
27 import org.apache.commons.jxpath.JXPathContext;
28 import org.apache.commons.jxpath.JXPathException;
29 import org.apache.commons.jxpath.JXPathInvalidSyntaxException;
30 import org.apache.commons.jxpath.NodeSet;
31 import org.apache.commons.jxpath.ri.Compiler;
32 import org.apache.commons.jxpath.ri.EvalContext;
33 import org.apache.commons.jxpath.ri.InfoSetUtil;
34 import org.apache.commons.jxpath.ri.axes.NodeSetContext;
35 import org.apache.commons.jxpath.ri.model.NodePointer;
36
37
38
39
40 public class CoreFunction extends Operation {
41
42 private static final Double ZERO = Double.valueOf(0);
43 private final int functionCode;
44
45
46
47
48
49
50
51 public CoreFunction(final int functionCode, final Expression[] args) {
52 super(args);
53 this.functionCode = functionCode;
54 }
55
56
57
58
59
60
61 private void assertArgCount(final int count) {
62 assertArgRange(count, count);
63 }
64
65
66
67
68
69
70
71 private void assertArgRange(final int min, final int max) {
72 final int ct = getArgumentCount();
73 if (ct < min || ct > max) {
74 throw new JXPathInvalidSyntaxException("Incorrect number of arguments: " + this);
75 }
76 }
77
78 @Override
79 public Object compute(final EvalContext context) {
80 return computeValue(context);
81 }
82
83
84
85
86
87
88 @Override
89 public boolean computeContextDependent() {
90 if (super.computeContextDependent()) {
91 return true;
92 }
93 switch (functionCode) {
94 case Compiler.FUNCTION_LAST:
95 case Compiler.FUNCTION_POSITION:
96 return true;
97 case Compiler.FUNCTION_BOOLEAN:
98 case Compiler.FUNCTION_LOCAL_NAME:
99 case Compiler.FUNCTION_NAME:
100 case Compiler.FUNCTION_NAMESPACE_URI:
101 case Compiler.FUNCTION_STRING:
102 case Compiler.FUNCTION_LANG:
103 case Compiler.FUNCTION_NUMBER:
104 return args == null || args.length == 0;
105 case Compiler.FUNCTION_FORMAT_NUMBER:
106 return args != null && args.length == 2;
107 case Compiler.FUNCTION_COUNT:
108 case Compiler.FUNCTION_ID:
109 case Compiler.FUNCTION_CONCAT:
110 case Compiler.FUNCTION_STARTS_WITH:
111 case Compiler.FUNCTION_ENDS_WITH:
112 case Compiler.FUNCTION_CONTAINS:
113 case Compiler.FUNCTION_SUBSTRING_BEFORE:
114 case Compiler.FUNCTION_SUBSTRING_AFTER:
115 case Compiler.FUNCTION_SUBSTRING:
116 case Compiler.FUNCTION_STRING_LENGTH:
117 case Compiler.FUNCTION_NORMALIZE_SPACE:
118 case Compiler.FUNCTION_TRANSLATE:
119 case Compiler.FUNCTION_NOT:
120 case Compiler.FUNCTION_TRUE:
121 case Compiler.FUNCTION_FALSE:
122 case Compiler.FUNCTION_SUM:
123 case Compiler.FUNCTION_FLOOR:
124 case Compiler.FUNCTION_CEILING:
125 case Compiler.FUNCTION_ROUND:
126 default:
127 return false;
128 }
129 }
130
131 @Override
132 public Object computeValue(final EvalContext context) {
133 switch (functionCode) {
134 case Compiler.FUNCTION_LAST:
135 return functionLast(context);
136 case Compiler.FUNCTION_POSITION:
137 return functionPosition(context);
138 case Compiler.FUNCTION_COUNT:
139 return functionCount(context);
140 case Compiler.FUNCTION_LANG:
141 return functionLang(context);
142 case Compiler.FUNCTION_ID:
143 return functionID(context);
144 case Compiler.FUNCTION_LOCAL_NAME:
145 return functionLocalName(context);
146 case Compiler.FUNCTION_NAMESPACE_URI:
147 return functionNamespaceURI(context);
148 case Compiler.FUNCTION_NAME:
149 return functionName(context);
150 case Compiler.FUNCTION_STRING:
151 return functionString(context);
152 case Compiler.FUNCTION_CONCAT:
153 return functionConcat(context);
154 case Compiler.FUNCTION_STARTS_WITH:
155 return functionStartsWith(context);
156 case Compiler.FUNCTION_ENDS_WITH:
157 return functionEndsWith(context);
158 case Compiler.FUNCTION_CONTAINS:
159 return functionContains(context);
160 case Compiler.FUNCTION_SUBSTRING_BEFORE:
161 return functionSubstringBefore(context);
162 case Compiler.FUNCTION_SUBSTRING_AFTER:
163 return functionSubstringAfter(context);
164 case Compiler.FUNCTION_SUBSTRING:
165 return functionSubstring(context);
166 case Compiler.FUNCTION_STRING_LENGTH:
167 return functionStringLength(context);
168 case Compiler.FUNCTION_NORMALIZE_SPACE:
169 return functionNormalizeSpace(context);
170 case Compiler.FUNCTION_TRANSLATE:
171 return functionTranslate(context);
172 case Compiler.FUNCTION_BOOLEAN:
173 return functionBoolean(context);
174 case Compiler.FUNCTION_NOT:
175 return functionNot(context);
176 case Compiler.FUNCTION_TRUE:
177 return functionTrue(context);
178 case Compiler.FUNCTION_FALSE:
179 return functionFalse(context);
180 case Compiler.FUNCTION_NULL:
181 return functionNull(context);
182 case Compiler.FUNCTION_NUMBER:
183 return functionNumber(context);
184 case Compiler.FUNCTION_SUM:
185 return functionSum(context);
186 case Compiler.FUNCTION_FLOOR:
187 return functionFloor(context);
188 case Compiler.FUNCTION_CEILING:
189 return functionCeiling(context);
190 case Compiler.FUNCTION_ROUND:
191 return functionRound(context);
192 case Compiler.FUNCTION_KEY:
193 return functionKey(context);
194 case Compiler.FUNCTION_FORMAT_NUMBER:
195 return functionFormatNumber(context);
196 default:
197 return null;
198 }
199 }
200
201
202
203
204
205
206
207 protected Object functionBoolean(final EvalContext context) {
208 assertArgCount(1);
209 return InfoSetUtil.booleanValue(getArg1().computeValue(context)) ? Boolean.TRUE : Boolean.FALSE;
210 }
211
212
213
214
215
216
217
218 protected Object functionCeiling(final EvalContext context) {
219 assertArgCount(1);
220 final double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
221 if (Double.isNaN(v) || Double.isInfinite(v)) {
222 return Double.valueOf(v);
223 }
224 return Double.valueOf(Math.ceil(v));
225 }
226
227
228
229
230
231
232
233 protected Object functionConcat(final EvalContext context) {
234 if (getArgumentCount() < 2) {
235 assertArgCount(2);
236 }
237 final StringBuilder buffer = new StringBuilder();
238 final Expression[] args = getArguments();
239 for (final Expression arg : args) {
240 buffer.append(InfoSetUtil.stringValue(arg.compute(context)));
241 }
242 return buffer.toString();
243 }
244
245
246
247
248
249
250
251 protected Object functionContains(final EvalContext context) {
252 assertArgCount(2);
253 final String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
254 final String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
255 return Boolean.valueOf(s1.contains(s2));
256 }
257
258
259
260
261
262
263
264 protected Object functionCount(final EvalContext context) {
265 assertArgCount(1);
266 final Expression arg1 = getArg1();
267 int count = 0;
268 Object value = arg1.compute(context);
269 if (value instanceof NodePointer) {
270 value = ((NodePointer) value).getValue();
271 }
272 if (value instanceof EvalContext) {
273 final EvalContext ctx = (EvalContext) value;
274 while (ctx.hasNext()) {
275 ctx.next();
276 count++;
277 }
278 } else if (value instanceof Collection) {
279 count = ((Collection) value).size();
280 } else if (value == null) {
281 count = 0;
282 } else {
283 count = 1;
284 }
285 return Double.valueOf(count);
286 }
287
288
289
290
291
292
293
294
295 protected Object functionEndsWith(final EvalContext context) {
296 assertArgCount(2);
297 final String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
298 final String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
299 return s1.endsWith(s2) ? Boolean.TRUE : Boolean.FALSE;
300 }
301
302
303
304
305
306
307
308 protected Object functionFalse(final EvalContext context) {
309 assertArgCount(0);
310 return Boolean.FALSE;
311 }
312
313
314
315
316
317
318
319 protected Object functionFloor(final EvalContext context) {
320 assertArgCount(1);
321 final double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
322 if (Double.isNaN(v) || Double.isInfinite(v)) {
323 return Double.valueOf(v);
324 }
325 return Double.valueOf(Math.floor(v));
326 }
327
328
329
330
331
332
333
334 private Object functionFormatNumber(final EvalContext context) {
335 final int minArgs = 2;
336 final int maxArgs = 3;
337 assertArgRange(minArgs, maxArgs);
338 final double number = InfoSetUtil.doubleValue(getArg1().computeValue(context));
339 final String pattern = InfoSetUtil.stringValue(getArg2().computeValue(context));
340 DecimalFormatSymbols symbols;
341 if (getArgumentCount() == maxArgs) {
342 final String symbolsName = InfoSetUtil.stringValue(getArg3().computeValue(context));
343 symbols = context.getJXPathContext().getDecimalFormatSymbols(symbolsName);
344 } else {
345 final NodePointer pointer = context.getCurrentNodePointer();
346 Locale locale;
347 if (pointer != null) {
348 locale = pointer.getLocale();
349 } else {
350 locale = context.getJXPathContext().getLocale();
351 }
352 symbols = new DecimalFormatSymbols(locale);
353 }
354 final DecimalFormat format = (DecimalFormat) NumberFormat.getInstance();
355 format.setDecimalFormatSymbols(symbols);
356 format.applyLocalizedPattern(pattern);
357 return format.format(number);
358 }
359
360
361
362
363
364
365
366 protected Object functionID(final EvalContext context) {
367 assertArgCount(1);
368 final String id = InfoSetUtil.stringValue(getArg1().computeValue(context));
369 final JXPathContext jxpathContext = context.getJXPathContext();
370 final NodePointer pointer = (NodePointer) jxpathContext.getContextPointer();
371 return pointer.getPointerByID(jxpathContext, id);
372 }
373
374
375
376
377
378
379
380 protected Object functionKey(final EvalContext context) {
381 assertArgCount(2);
382 final String key = InfoSetUtil.stringValue(getArg1().computeValue(context));
383 Object value = getArg2().compute(context);
384 EvalContext ec = null;
385 if (value instanceof EvalContext) {
386 ec = (EvalContext) value;
387 if (!ec.hasNext()) {
388 return new NodeSetContext(context, new BasicNodeSet());
389 }
390 value = ((NodePointer) ec.next()).getValue();
391 }
392 final JXPathContext jxpathContext = context.getJXPathContext();
393 NodeSet nodeSet = jxpathContext.getNodeSetByKey(key, value);
394 if (ec != null && ec.hasNext()) {
395 final BasicNodeSet accum = new BasicNodeSet();
396 accum.add(nodeSet);
397 while (ec.hasNext()) {
398 value = ((NodePointer) ec.next()).getValue();
399 accum.add(jxpathContext.getNodeSetByKey(key, value));
400 }
401 nodeSet = accum;
402 }
403 return new NodeSetContext(context, nodeSet);
404 }
405
406
407
408
409
410
411
412 protected Object functionLang(final EvalContext context) {
413 assertArgCount(1);
414 final String lang = InfoSetUtil.stringValue(getArg1().computeValue(context));
415 final NodePointer pointer = (NodePointer) context.getSingleNodePointer();
416 if (pointer == null) {
417 return Boolean.FALSE;
418 }
419 return pointer.isLanguage(lang) ? Boolean.TRUE : Boolean.FALSE;
420 }
421
422
423
424
425
426
427
428 protected Object functionLast(final EvalContext context) {
429 assertArgCount(0);
430
431
432 final int old = context.getCurrentPosition();
433 context.reset();
434 int count = 0;
435 while (context.nextNode()) {
436 count++;
437 }
438
439 if (old != 0) {
440 context.setPosition(old);
441 }
442 return Double.valueOf(count);
443 }
444
445
446
447
448
449
450
451 protected Object functionLocalName(final EvalContext context) {
452 if (getArgumentCount() == 0) {
453 final NodePointer ptr = context.getCurrentNodePointer();
454 return ptr.getName().getName();
455 }
456 assertArgCount(1);
457 final Object set = getArg1().compute(context);
458 if (set instanceof EvalContext) {
459 final EvalContext ctx = (EvalContext) set;
460 if (ctx.hasNext()) {
461 final NodePointer ptr = (NodePointer) ctx.next();
462 return ptr.getName().getName();
463 }
464 }
465 return "";
466 }
467
468
469
470
471
472
473
474 protected Object functionName(final EvalContext context) {
475 if (getArgumentCount() == 0) {
476 final NodePointer ptr = context.getCurrentNodePointer();
477 return ptr.getName().toString();
478 }
479 assertArgCount(1);
480 final Object set = getArg1().compute(context);
481 if (set instanceof EvalContext) {
482 final EvalContext ctx = (EvalContext) set;
483 if (ctx.hasNext()) {
484 final NodePointer ptr = (NodePointer) ctx.next();
485 return ptr.getName().toString();
486 }
487 }
488 return "";
489 }
490
491
492
493
494
495
496
497 protected Object functionNamespaceURI(final EvalContext context) {
498 if (getArgumentCount() == 0) {
499 final NodePointer ptr = context.getCurrentNodePointer();
500 final String str = ptr.getNamespaceURI();
501 return str == null ? "" : str;
502 }
503 assertArgCount(1);
504 final Object set = getArg1().compute(context);
505 if (set instanceof EvalContext) {
506 final EvalContext ctx = (EvalContext) set;
507 if (ctx.hasNext()) {
508 final NodePointer ptr = (NodePointer) ctx.next();
509 final String str = ptr.getNamespaceURI();
510 return str == null ? "" : str;
511 }
512 }
513 return "";
514 }
515
516
517
518
519
520
521
522 protected Object functionNormalizeSpace(final EvalContext context) {
523 assertArgCount(1);
524 final String s = InfoSetUtil.stringValue(getArg1().computeValue(context));
525 final char[] chars = s.toCharArray();
526 int out = 0;
527 int phase = 0;
528 for (int in = 0; in < chars.length; in++) {
529 switch (chars[in]) {
530 case ' ':
531 case '\t':
532 case '\r':
533 case '\n':
534 if (phase == 1) {
535 phase = 2;
536 chars[out++] = ' ';
537 }
538 break;
539 default:
540 chars[out++] = chars[in];
541 phase = 1;
542 }
543 }
544 if (phase == 2) {
545 out--;
546 }
547 return new String(chars, 0, out);
548 }
549
550
551
552
553
554
555
556 protected Object functionNot(final EvalContext context) {
557 assertArgCount(1);
558 return InfoSetUtil.booleanValue(getArg1().computeValue(context)) ? Boolean.FALSE : Boolean.TRUE;
559 }
560
561
562
563
564
565
566
567 protected Object functionNull(final EvalContext context) {
568 assertArgCount(0);
569 return null;
570 }
571
572
573
574
575
576
577
578 protected Object functionNumber(final EvalContext context) {
579 if (getArgumentCount() == 0) {
580 return InfoSetUtil.number(context.getCurrentNodePointer());
581 }
582 assertArgCount(1);
583 return InfoSetUtil.number(getArg1().computeValue(context));
584 }
585
586
587
588
589
590
591
592 protected Object functionPosition(final EvalContext context) {
593 assertArgCount(0);
594 return Integer.valueOf(context.getCurrentPosition());
595 }
596
597
598
599
600
601
602
603 protected Object functionRound(final EvalContext context) {
604 assertArgCount(1);
605 final double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
606 if (Double.isNaN(v) || Double.isInfinite(v)) {
607 return Double.valueOf(v);
608 }
609 return Double.valueOf(Math.round(v));
610 }
611
612
613
614
615
616
617
618 protected Object functionStartsWith(final EvalContext context) {
619 assertArgCount(2);
620 final String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
621 final String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
622 return s1.startsWith(s2) ? Boolean.TRUE : Boolean.FALSE;
623 }
624
625
626
627
628
629
630
631 protected Object functionString(final EvalContext context) {
632 if (getArgumentCount() == 0) {
633 return InfoSetUtil.stringValue(context.getCurrentNodePointer());
634 }
635 assertArgCount(1);
636 return InfoSetUtil.stringValue(getArg1().computeValue(context));
637 }
638
639
640
641
642
643
644
645 protected Object functionStringLength(final EvalContext context) {
646 String s;
647 if (getArgumentCount() == 0) {
648 s = InfoSetUtil.stringValue(context.getCurrentNodePointer());
649 } else {
650 assertArgCount(1);
651 s = InfoSetUtil.stringValue(getArg1().computeValue(context));
652 }
653 return Double.valueOf(s.length());
654 }
655
656
657
658
659
660
661
662 protected Object functionSubstring(final EvalContext context) {
663 final int minArgs = 2;
664 final int maxArgs = 3;
665 assertArgRange(minArgs, maxArgs);
666 final int ac = getArgumentCount();
667 final String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
668 double from = InfoSetUtil.doubleValue(getArg2().computeValue(context));
669 if (Double.isNaN(from)) {
670 return "";
671 }
672 from = Math.round(from);
673 if (from > s1.length() + 1) {
674 return "";
675 }
676 if (ac == 2) {
677 if (from < 1) {
678 from = 1;
679 }
680 return s1.substring((int) from - 1);
681 }
682 double length = InfoSetUtil.doubleValue(getArg3().computeValue(context));
683 length = Math.round(length);
684 if (length < 0) {
685 return "";
686 }
687 final double to = from + length;
688 if (to < 1) {
689 return "";
690 }
691 if (to > s1.length() + 1) {
692 if (from < 1) {
693 from = 1;
694 }
695 return s1.substring((int) from - 1);
696 }
697 if (from < 1) {
698 from = 1;
699 }
700 return s1.substring((int) from - 1, (int) (to - 1));
701 }
702
703
704
705
706
707
708
709 protected Object functionSubstringAfter(final EvalContext context) {
710 assertArgCount(2);
711 final String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
712 final String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
713 final int index = s1.indexOf(s2);
714 if (index == -1) {
715 return "";
716 }
717 return s1.substring(index + s2.length());
718 }
719
720
721
722
723
724
725
726 protected Object functionSubstringBefore(final EvalContext context) {
727 assertArgCount(2);
728 final String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
729 final String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
730 final int index = s1.indexOf(s2);
731 if (index == -1) {
732 return "";
733 }
734 return s1.substring(0, index);
735 }
736
737
738
739
740
741
742
743 protected Object functionSum(final EvalContext context) {
744 assertArgCount(1);
745 final Object v = getArg1().compute(context);
746 if (v == null) {
747 return ZERO;
748 }
749 if (v instanceof EvalContext) {
750 double sum = 0.0;
751 final EvalContext ctx = (EvalContext) v;
752 while (ctx.hasNext()) {
753 final NodePointer ptr = (NodePointer) ctx.next();
754 sum += InfoSetUtil.doubleValue(ptr);
755 }
756 return Double.valueOf(sum);
757 }
758 throw new JXPathException("Invalid argument type for 'sum': " + v.getClass().getName());
759 }
760
761
762
763
764
765
766
767 protected Object functionTranslate(final EvalContext context) {
768 final int argCount = 3;
769 assertArgCount(argCount);
770 final String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
771 final String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
772 final String s3 = InfoSetUtil.stringValue(getArg3().computeValue(context));
773 final char[] chars = s1.toCharArray();
774 int out = 0;
775 for (int in = 0; in < chars.length; in++) {
776 final char c = chars[in];
777 final int inx = s2.indexOf(c);
778 if (inx != -1) {
779 if (inx < s3.length()) {
780 chars[out++] = s3.charAt(inx);
781 }
782 } else {
783 chars[out++] = c;
784 }
785 }
786 return new String(chars, 0, out);
787 }
788
789
790
791
792
793
794
795 protected Object functionTrue(final EvalContext context) {
796 assertArgCount(0);
797 return Boolean.TRUE;
798 }
799
800
801
802
803
804
805 public Expression getArg1() {
806 return args[0];
807 }
808
809
810
811
812
813
814 public Expression getArg2() {
815 return args[1];
816 }
817
818
819
820
821
822
823 public Expression getArg3() {
824 return args[2];
825 }
826
827
828
829
830
831
832 public int getArgumentCount() {
833 if (args == null) {
834 return 0;
835 }
836 return args.length;
837 }
838
839
840
841
842
843
844 public int getFunctionCode() {
845 return functionCode;
846 }
847
848
849
850
851
852
853 protected String getFunctionName() {
854 switch (functionCode) {
855 case Compiler.FUNCTION_LAST:
856 return "last";
857 case Compiler.FUNCTION_POSITION:
858 return "position";
859 case Compiler.FUNCTION_COUNT:
860 return "count";
861 case Compiler.FUNCTION_ID:
862 return "id";
863 case Compiler.FUNCTION_LOCAL_NAME:
864 return "local-name";
865 case Compiler.FUNCTION_NAMESPACE_URI:
866 return "namespace-uri";
867 case Compiler.FUNCTION_NAME:
868 return "name";
869 case Compiler.FUNCTION_STRING:
870 return "string";
871 case Compiler.FUNCTION_CONCAT:
872 return "concat";
873 case Compiler.FUNCTION_STARTS_WITH:
874 return "starts-with";
875 case Compiler.FUNCTION_ENDS_WITH:
876 return "ends-with";
877 case Compiler.FUNCTION_CONTAINS:
878 return "contains";
879 case Compiler.FUNCTION_SUBSTRING_BEFORE:
880 return "substring-before";
881 case Compiler.FUNCTION_SUBSTRING_AFTER:
882 return "substring-after";
883 case Compiler.FUNCTION_SUBSTRING:
884 return "substring";
885 case Compiler.FUNCTION_STRING_LENGTH:
886 return "string-length";
887 case Compiler.FUNCTION_NORMALIZE_SPACE:
888 return "normalize-space";
889 case Compiler.FUNCTION_TRANSLATE:
890 return "translate";
891 case Compiler.FUNCTION_BOOLEAN:
892 return "boolean";
893 case Compiler.FUNCTION_NOT:
894 return "not";
895 case Compiler.FUNCTION_TRUE:
896 return "true";
897 case Compiler.FUNCTION_FALSE:
898 return "false";
899 case Compiler.FUNCTION_LANG:
900 return "lang";
901 case Compiler.FUNCTION_NUMBER:
902 return "number";
903 case Compiler.FUNCTION_SUM:
904 return "sum";
905 case Compiler.FUNCTION_FLOOR:
906 return "floor";
907 case Compiler.FUNCTION_CEILING:
908 return "ceiling";
909 case Compiler.FUNCTION_ROUND:
910 return "round";
911 case Compiler.FUNCTION_KEY:
912 return "key";
913 case Compiler.FUNCTION_FORMAT_NUMBER:
914 return "format-number";
915 default:
916 return "unknownFunction" + functionCode + "()";
917 }
918 }
919
920 @Override
921 public String toString() {
922 final StringBuilder buffer = new StringBuilder();
923 buffer.append(getFunctionName());
924 buffer.append('(');
925 final Expression[] args = getArguments();
926 if (args != null) {
927 for (int i = 0; i < args.length; i++) {
928 if (i > 0) {
929 buffer.append(", ");
930 }
931 buffer.append(args[i]);
932 }
933 }
934 buffer.append(')');
935 return buffer.toString();
936 }
937 }