1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.ir; 27 28 import java.util.Arrays; 29 import java.util.Collections; 30 import java.util.List; 31 import jdk.nashorn.internal.codegen.CompileUnit; 32 import jdk.nashorn.internal.codegen.types.Type; 33 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 34 import jdk.nashorn.internal.parser.Lexer.LexerToken; 35 import jdk.nashorn.internal.parser.Token; 36 import jdk.nashorn.internal.parser.TokenType; 37 import jdk.nashorn.internal.runtime.JSType; 38 import jdk.nashorn.internal.runtime.ScriptRuntime; 39 import jdk.nashorn.internal.runtime.Source; 40 import jdk.nashorn.internal.runtime.Undefined; 41 42 /** 43 * Literal nodes represent JavaScript values. 44 * 45 * @param <T> the literal type 46 */ 47 public abstract class LiteralNode<T> extends Node implements PropertyKey { 48 /** Literal value */ 49 protected T value; 50 51 /** 52 * Constructor 53 * 54 * @param source the source 55 * @param token token 56 * @param finish finish 57 * @param value the value of the literal 58 */ 59 protected LiteralNode(final Source source, final long token, final int finish, final T value) { 60 super(source, token, finish); 61 this.value = value; 62 } 63 64 /** 65 * Copy constructor 66 * 67 * @param literalNode source node 68 */ 69 protected LiteralNode(final LiteralNode<T> literalNode) { 70 super(literalNode); 71 this.value = literalNode.value; 72 } 73 74 @Override 75 public boolean isAtom() { 76 return true; 77 } 78 79 /** 80 * Check if the literal value is null 81 * @return true if literal value is null 82 */ 83 public boolean isNull() { 84 return value == null; 85 } 86 87 @Override 88 public int hashCode() { 89 return value == null ? 0 : value.hashCode(); 90 } 91 92 @Override 93 public boolean equals(final Object other) { 94 if (!(other instanceof LiteralNode<?>)) { 95 return false; 96 } 97 final LiteralNode<?> otherNode = (LiteralNode<?>)other; 98 if (otherNode.isNull()) { 99 return isNull(); 100 } 101 return ((LiteralNode<?>)other).getValue().equals(value); 102 } 103 104 /** 105 * Check if the literal value is boolean true 106 * @return true if literal value is boolean true 107 */ 108 public boolean isTrue() { 109 return JSType.toBoolean(value); 110 } 111 112 @Override 113 public Type getType() { 114 return Type.typeFor(value.getClass()); 115 } 116 117 @Override 118 public String getPropertyName() { 119 return JSType.toString(getObject()); 120 } 121 122 /** 123 * Fetch boolean value of node. 124 * 125 * @return boolean value of node. 126 */ 127 public boolean getBoolean() { 128 return JSType.toBoolean(value); 129 } 130 131 /** 132 * Fetch int32 value of node. 133 * 134 * @return Int32 value of node. 135 */ 136 public int getInt32() { 137 return JSType.toInt32(value); 138 } 139 140 /** 141 * Fetch uint32 value of node. 142 * 143 * @return uint32 value of node. 144 */ 145 public long getUint32() { 146 return JSType.toUint32(value); 147 } 148 149 /** 150 * Fetch long value of node 151 * 152 * @return long value of node 153 */ 154 public long getLong() { 155 return JSType.toLong(value); 156 } 157 158 /** 159 * Fetch double value of node. 160 * 161 * @return double value of node. 162 */ 163 public double getNumber() { 164 return JSType.toNumber(value); 165 } 166 167 /** 168 * Get the array value of the node 169 * 170 * @return the array value 171 */ 172 public Node[] getArray() { 173 assert false : "not an array node"; 174 return null; 175 } 176 177 /** 178 * Fetch String value of node. 179 * 180 * @return String value of node. 181 */ 182 public String getString() { 183 return JSType.toString(value); 184 } 185 186 /** 187 * Fetch Object value of node. 188 * 189 * @return Object value of node. 190 */ 191 public Object getObject() { 192 return value; 193 } 194 195 /** 196 * Test if the value is a string. 197 * 198 * @return True if value is a string. 199 */ 200 public boolean isString() { 201 return value instanceof String; 202 } 203 204 /** 205 * Test if tha value is a number 206 * 207 * @return True if value is a number 208 */ 209 public boolean isNumeric() { 210 return value instanceof Number; 211 } 212 213 /** 214 * Assist in IR navigation. 215 * 216 * @param visitor IR navigating visitor. 217 */ 218 @Override 219 public Node accept(final NodeVisitor visitor) { 220 if (visitor.enter(this) != null) { 221 return visitor.leave(this); 222 } 223 224 return this; 225 } 226 227 @Override 228 public void toString(final StringBuilder sb) { 229 if (value == null) { 230 sb.append("null"); 231 } else { 232 sb.append(value.toString()); 233 } 234 } 235 236 /** 237 * Get the literal node value 238 * @return the value 239 */ 240 public T getValue() { 241 return value; 242 } 243 244 /** 245 * Create a new null literal 246 * 247 * @param source the source 248 * @param token token 249 * @param finish finish 250 * 251 * @return the new literal node 252 */ 253 public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish) { 254 return new NodeLiteralNode(source, token, finish); 255 } 256 257 /** 258 * Create a new null literal based on a parent node (source, token, finish) 259 * 260 * @param parent parent node 261 * 262 * @return the new literal node 263 */ 264 public static LiteralNode<?> newInstance(final Node parent) { 265 return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish()); 266 } 267 268 private static class BooleanLiteralNode extends LiteralNode<Boolean> { 269 270 private BooleanLiteralNode(final Source source, final long token, final int finish, final boolean value) { 271 super(source, Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value); 272 } 273 274 private BooleanLiteralNode(final BooleanLiteralNode literalNode) { 275 super(literalNode); 276 } 277 278 @Override 279 protected Node copy(final CopyState cs) { 280 return new BooleanLiteralNode(this); 281 } 282 283 @Override 284 public boolean isTrue() { 285 return value; 286 } 287 288 @Override 289 public Type getType() { 290 return Type.BOOLEAN; 291 } 292 293 @Override 294 public Type getWidestOperationType() { 295 return Type.BOOLEAN; 296 } 297 } 298 299 /** 300 * Create a new boolean literal 301 * 302 * @param source the source 303 * @param token token 304 * @param finish finish 305 * @param value true or false 306 * 307 * @return the new literal node 308 */ 309 public static LiteralNode<Boolean> newInstance(final Source source, final long token, final int finish, final boolean value) { 310 return new BooleanLiteralNode(source, token, finish, value); 311 } 312 313 /** 314 * Create a new boolean literal based on a parent node (source, token, finish) 315 * 316 * @param parent parent node 317 * @param value true or false 318 * 319 * @return the new literal node 320 */ 321 public static LiteralNode<?> newInstance(final Node parent, final boolean value) { 322 return new BooleanLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 323 } 324 325 private static class NumberLiteralNode extends LiteralNode<Number> { 326 327 private final Type type = numberGetType(value); 328 329 private NumberLiteralNode(final Source source, final long token, final int finish, final Number value) { 330 super(source, Token.recast(token, TokenType.DECIMAL), finish, value); 331 } 332 333 private NumberLiteralNode(final NumberLiteralNode literalNode) { 334 super(literalNode); 335 } 336 337 private static Type numberGetType(final Number number) { 338 if (number instanceof Integer) { 339 return Type.INT; 340 } else if (number instanceof Long) { 341 return Type.LONG; 342 } else if (number instanceof Double) { 343 return Type.NUMBER; 344 } else { 345 assert false; 346 } 347 348 return null; 349 } 350 351 @Override 352 protected Node copy(final CopyState cs) { 353 return new NumberLiteralNode(this); 354 } 355 356 @Override 357 public Type getType() { 358 return type; 359 } 360 361 @Override 362 public Type getWidestOperationType() { 363 return getType(); 364 } 365 366 } 367 /** 368 * Create a new number literal 369 * 370 * @param source the source 371 * @param token token 372 * @param finish finish 373 * @param value literal value 374 * 375 * @return the new literal node 376 */ 377 public static LiteralNode<Number> newInstance(final Source source, final long token, final int finish, final Number value) { 378 return new NumberLiteralNode(source, token, finish, value); 379 } 380 381 /** 382 * Create a new number literal based on a parent node (source, token, finish) 383 * 384 * @param parent parent node 385 * @param value literal value 386 * 387 * @return the new literal node 388 */ 389 public static LiteralNode<?> newInstance(final Node parent, final Number value) { 390 return new NumberLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 391 } 392 393 private static class UndefinedLiteralNode extends LiteralNode<Undefined> { 394 private UndefinedLiteralNode(final Source source, final long token, final int finish) { 395 super(source, Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED); 396 } 397 398 private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) { 399 super(literalNode); 400 } 401 402 @Override 403 protected Node copy(final CopyState cs) { 404 return new UndefinedLiteralNode(this); 405 } 406 } 407 408 /** 409 * Create a new undefined literal 410 * 411 * @param source the source 412 * @param token token 413 * @param finish finish 414 * @param value undefined value, passed only for polymorphisism discrimination 415 * 416 * @return the new literal node 417 */ 418 public static LiteralNode<Undefined> newInstance(final Source source, final long token, final int finish, final Undefined value) { 419 return new UndefinedLiteralNode(source, token, finish); 420 } 421 422 /** 423 * Create a new null literal based on a parent node (source, token, finish) 424 * 425 * @param parent parent node 426 * @param value undefined value 427 * 428 * @return the new literal node 429 */ 430 public static LiteralNode<?> newInstance(final Node parent, final Undefined value) { 431 return new UndefinedLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish()); 432 } 433 434 private static class StringLiteralNode extends LiteralNode<String> { 435 private StringLiteralNode(final Source source, final long token, final int finish, final String value) { 436 super(source, Token.recast(token, TokenType.STRING), finish, value); 437 } 438 439 private StringLiteralNode(final StringLiteralNode literalNode) { 440 super(literalNode); 441 } 442 443 @Override 444 protected Node copy(final CopyState cs) { 445 return new StringLiteralNode(this); 446 } 447 448 @Override 449 public void toString(final StringBuilder sb) { 450 sb.append('\"'); 451 sb.append(value); 452 sb.append('\"'); 453 } 454 } 455 456 /** 457 * Create a new string literal 458 * 459 * @param source the source 460 * @param token token 461 * @param finish finish 462 * @param value string value 463 * 464 * @return the new literal node 465 */ 466 public static LiteralNode<String> newInstance(final Source source, final long token, final int finish, final String value) { 467 return new StringLiteralNode(source, token, finish, value); 468 } 469 470 /** 471 * Create a new String literal based on a parent node (source, token, finish) 472 * 473 * @param parent parent node 474 * @param value string value 475 * 476 * @return the new literal node 477 */ 478 public static LiteralNode<?> newInstance(final Node parent, final String value) { 479 return new StringLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 480 } 481 482 private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> { 483 private LexerTokenLiteralNode(final Source source, final long token, final int finish, final LexerToken value) { 484 super(source, Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here? 485 } 486 487 private LexerTokenLiteralNode(final LexerTokenLiteralNode literalNode) { 488 super(literalNode); 489 } 490 491 @Override 492 protected Node copy(final CopyState cs) { 493 return new LexerTokenLiteralNode(this); 494 } 495 496 @Override 497 public void toString(final StringBuilder sb) { 498 sb.append(value.toString()); 499 } 500 } 501 502 /** 503 * Create a new literal node for a lexer token 504 * 505 * @param source the source 506 * @param token token 507 * @param finish finish 508 * @param value lexer token value 509 * 510 * @return the new literal node 511 */ 512 public static LiteralNode<LexerToken> newInstance(final Source source, final long token, final int finish, final LexerToken value) { 513 return new LexerTokenLiteralNode(source, token, finish, value); 514 } 515 516 /** 517 * Create a new lexer token literal based on a parent node (source, token, finish) 518 * 519 * @param parent parent node 520 * @param value lexer token 521 * 522 * @return the new literal node 523 */ 524 public static LiteralNode<?> newInstance(final Node parent, final LexerToken value) { 525 return new LexerTokenLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 526 } 527 528 private static class NodeLiteralNode extends LiteralNode<Node> { 529 530 private NodeLiteralNode(final Source source, final long token, final int finish) { 531 this(source, token, finish, null); 532 } 533 534 private NodeLiteralNode(final Source source, final long token, final int finish, final Node value) { 535 super(source, Token.recast(token, TokenType.OBJECT), finish, value); 536 } 537 538 private NodeLiteralNode(final LiteralNode<Node> literalNode) { 539 super(literalNode); 540 } 541 542 @Override 543 protected Node copy(final CopyState cs) { 544 return new NodeLiteralNode(this); 545 } 546 547 @Override 548 public Node accept(final NodeVisitor visitor) { 549 if (visitor.enter(this) != null) { 550 if (value != null) { 551 value = value.accept(visitor); 552 } 553 return visitor.leave(this); 554 } 555 556 return this; 557 } 558 559 @Override 560 public Type getType() { 561 return value == null ? Type.OBJECT : super.getType(); 562 } 563 564 @Override 565 public Type getWidestOperationType() { 566 return value == null ? Type.OBJECT : value.getWidestOperationType(); 567 } 568 569 } 570 /** 571 * Create a new node literal for an arbitrary node 572 * 573 * @param source the source 574 * @param token token 575 * @param finish finish 576 * @param value the literal value node 577 * 578 * @return the new literal node 579 */ 580 public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish, final Node value) { 581 return new NodeLiteralNode(source, token, finish, value); 582 } 583 584 /** 585 * Create a new node literal based on a parent node (source, token, finish) 586 * 587 * @param parent parent node 588 * @param value node value 589 * 590 * @return the new literal node 591 */ 592 public static LiteralNode<?> newInstance(final Node parent, final Node value) { 593 return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 594 } 595 596 /** 597 * Array literal node class. 598 */ 599 public static class ArrayLiteralNode extends LiteralNode<Node[]> { 600 private static class PostsetMarker { 601 //empty 602 } 603 604 private static PostsetMarker POSTSET_MARKER = new PostsetMarker(); 605 606 /** Array element type. */ 607 private Type elementType; 608 609 /** Preset constant array. */ 610 private Object presets; 611 612 /** Indices of array elements requiring computed post sets. */ 613 private int[] postsets; 614 615 private List<ArrayUnit> units; 616 617 /** 618 * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can 619 * be split if they are too large, for bytecode generation reasons 620 */ 621 public static class ArrayUnit { 622 /** Compile unit associated with the postsets range. */ 623 private final CompileUnit compileUnit; 624 625 /** postsets range associated with the unit (hi not inclusive). */ 626 private final int lo, hi; 627 628 /** 629 * Constructor 630 * @param compileUnit compile unit 631 * @param lo lowest array index in unit 632 * @param hi highest array index in unit + 1 633 */ 634 public ArrayUnit(final CompileUnit compileUnit, final int lo, final int hi) { 635 this.compileUnit = compileUnit; 636 this.lo = lo; 637 this.hi = hi; 638 } 639 640 /** 641 * Get the high index position of the ArrayUnit (non inclusive) 642 * @return high index position 643 */ 644 public int getHi() { 645 return hi; 646 } 647 648 /** 649 * Get the low index position of the ArrayUnit (inclusive) 650 * @return low index position 651 */ 652 public int getLo() { 653 return lo; 654 } 655 656 /** 657 * The array compile unit 658 * @return array compile unit 659 */ 660 public CompileUnit getCompileUnit() { 661 return compileUnit; 662 } 663 } 664 665 /** 666 * Constructor 667 * 668 * @param source the source 669 * @param token token 670 * @param finish finish 671 * @param value array literal value, a Node array 672 */ 673 protected ArrayLiteralNode(final Source source, final long token, final int finish, final Node[] value) { 674 super(source, Token.recast(token, TokenType.ARRAY), finish, value); 675 this.elementType = Type.UNKNOWN; 676 } 677 678 /** 679 * Copy constructor 680 * @param node source array literal node 681 */ 682 protected ArrayLiteralNode(final ArrayLiteralNode node) { 683 super(node); 684 this.elementType = node.elementType; 685 } 686 687 @Override 688 protected Node copy(final CopyState cs) { 689 return new ArrayLiteralNode(this); 690 } 691 692 /** 693 * Compute things like widest element type needed. Internal use from compiler only 694 */ 695 public void analyze() { 696 elementType = Type.INT; 697 analyzeElements(); 698 699 if (elementType == Type.INT) { 700 presetIntArray(); 701 } else if (elementType.isNumeric()) { 702 presetNumberArray(); 703 } else { 704 presetObjectArray(); 705 } 706 } 707 708 private void presetIntArray() { 709 final int[] array = new int[value.length]; 710 final int[] computed = new int[value.length]; 711 int nComputed = 0; 712 713 for (int i = 0; i < value.length; i++) { 714 final Object element = objectAsConstant(value[i]); 715 716 if (element instanceof Number) { 717 array[i] = ((Number)element).intValue(); 718 } else { 719 computed[nComputed++] = i; 720 } 721 } 722 723 presets = array; 724 postsets = Arrays.copyOf(computed, nComputed); 725 } 726 727 private void presetNumberArray() { 728 final double[] array = new double[value.length]; 729 final int[] computed = new int[value.length]; 730 int nComputed = 0; 731 732 for (int i = 0; i < value.length; i++) { 733 final Object element = objectAsConstant(value[i]); 734 735 if (element instanceof Number) { 736 array[i] = ((Number)element).doubleValue(); 737 } else { 738 computed[nComputed++] = i; 739 } 740 } 741 742 presets = array; 743 postsets = Arrays.copyOf(computed, nComputed); 744 } 745 746 private void presetObjectArray() { 747 final Object[] array = new Object[value.length]; 748 final int[] computed = new int[value.length]; 749 int nComputed = 0; 750 751 for (int i = 0; i < value.length; i++) { 752 final Node node = value[i]; 753 754 if (node == null) { 755 computed[nComputed++] = i; 756 } else { 757 final Object element = objectAsConstant(node); 758 759 if (element != POSTSET_MARKER) { 760 array[i] = element; 761 } else { 762 computed[nComputed++] = i; 763 } 764 } 765 } 766 767 presets = array; 768 postsets = Arrays.copyOf(computed, nComputed); 769 } 770 771 private void analyzeElements() { 772 for (final Node node : value) { 773 if (node == null) { 774 elementType = elementType.widest(Type.OBJECT); //no way to represent undefined as number 775 break; 776 } 777 778 final Symbol symbol = node.getSymbol(); 779 assert symbol != null; //don't run this on unresolved nodes or you are in trouble 780 Type symbolType = symbol.getSymbolType(); 781 if (symbolType.isUnknown()) { 782 symbolType = Type.OBJECT; 783 } 784 785 if (symbolType.isBoolean()) { 786 elementType = elementType.widest(Type.OBJECT); 787 break; 788 } 789 790 elementType = elementType.widest(symbolType); 791 792 if (elementType.isObject()) { 793 break; 794 } 795 } 796 } 797 798 private Object objectAsConstant(final Object object) { 799 if (object == null) { 800 return null; 801 } else if (object instanceof Number || object instanceof String || object instanceof Boolean) { 802 return object; 803 } else if (object instanceof LiteralNode) { 804 return objectAsConstant(((LiteralNode<?>)object).getValue()); 805 } else if (object instanceof UnaryNode) { 806 final UnaryNode unaryNode = (UnaryNode)object; 807 808 if (unaryNode.isTokenType(TokenType.CONVERT) && unaryNode.getType().isObject()) { 809 return objectAsConstant(unaryNode.rhs()); 810 } 811 } 812 813 return POSTSET_MARKER; 814 } 815 816 @Override 817 public Node[] getArray() { 818 return value; 819 } 820 821 @Override 822 public Type getType() { 823 if (elementType.isInteger()) { 824 return Type.INT_ARRAY; 825 } else if (elementType.isNumeric()) { 826 return Type.NUMBER_ARRAY; 827 } else { 828 return Type.OBJECT_ARRAY; 829 } 830 } 831 832 /** 833 * Get the element type of this array literal 834 * @return element type 835 */ 836 public Type getElementType() { 837 return elementType; 838 } 839 840 /** 841 * Get indices of arrays containing computed post sets 842 * @return post set indices 843 */ 844 public int[] getPostsets() { 845 return postsets; 846 } 847 848 /** 849 * Get presets constant array 850 * @return presets array, always returns an array type 851 */ 852 public Object getPresets() { 853 return presets; 854 } 855 856 /** 857 * Get the array units that make up this ArrayLiteral 858 * @see ArrayUnit 859 * @return list of array units 860 */ 861 public List<ArrayUnit> getUnits() { 862 return units == null ? null : Collections.unmodifiableList(units); 863 } 864 865 /** 866 * Set the ArrayUnits that make up this ArrayLiteral 867 * @see ArrayUnit 868 * @param units list of array units 869 */ 870 public void setUnits(final List<ArrayUnit> units) { 871 this.units = units; 872 } 873 874 @Override 875 public Node accept(final NodeVisitor visitor) { 876 if (visitor.enter(this) != null) { 877 for (int i = 0; i < value.length; i++) { 878 final Node element = value[i]; 879 if (element != null) { 880 value[i] = element.accept(visitor); 881 } 882 } 883 return visitor.leave(this); 884 } 885 return this; 886 } 887 888 @Override 889 public void toString(final StringBuilder sb) { 890 sb.append('['); 891 boolean first = true; 892 for (final Node node : value) { 893 if (!first) { 894 sb.append(','); 895 sb.append(' '); 896 } 897 if (node == null) { 898 sb.append("undefined"); 899 } else { 900 node.toString(sb); 901 } 902 first = false; 903 } 904 sb.append(']'); 905 } 906 } 907 908 /** 909 * Create a new array literal of Nodes from a list of Node values 910 * 911 * @param source the source 912 * @param token token 913 * @param finish finish 914 * @param value literal value list 915 * 916 * @return the new literal node 917 */ 918 public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final List<Node> value) { 919 return new ArrayLiteralNode(source, token, finish, value.toArray(new Node[value.size()])); 920 } 921 922 923 /** 924 * Create a new array literal based on a parent node (source, token, finish) 925 * 926 * @param parent parent node 927 * @param value literal value list 928 * 929 * @return the new literal node 930 */ 931 public static LiteralNode<?> newInstance(final Node parent, final List<Node> value) { 932 return new ArrayLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()])); 933 } 934 935 /** 936 * Create a new array literal of Nodes 937 * 938 * @param source the source 939 * @param token token 940 * @param finish finish 941 * @param value literal value array 942 * 943 * @return the new literal node 944 */ 945 public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final Node[] value) { 946 return new ArrayLiteralNode(source, token, finish, value); 947 } 948 } --- EOF ---