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 Type getType() { 498 return Type.OBJECT; 499 } 500 501 @Override 502 public void toString(final StringBuilder sb) { 503 sb.append(value.toString()); 504 } 505 } 506 507 /** 508 * Create a new literal node for a lexer token 509 * 510 * @param source the source 511 * @param token token 512 * @param finish finish 513 * @param value lexer token value 514 * 515 * @return the new literal node 516 */ 517 public static LiteralNode<LexerToken> newInstance(final Source source, final long token, final int finish, final LexerToken value) { 518 return new LexerTokenLiteralNode(source, token, finish, value); 519 } 520 521 /** 522 * Create a new lexer token literal based on a parent node (source, token, finish) 523 * 524 * @param parent parent node 525 * @param value lexer token 526 * 527 * @return the new literal node 528 */ 529 public static LiteralNode<?> newInstance(final Node parent, final LexerToken value) { 530 return new LexerTokenLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 531 } 532 533 private static class NodeLiteralNode extends LiteralNode<Node> { 534 535 private NodeLiteralNode(final Source source, final long token, final int finish) { 536 this(source, token, finish, null); 537 } 538 539 private NodeLiteralNode(final Source source, final long token, final int finish, final Node value) { 540 super(source, Token.recast(token, TokenType.OBJECT), finish, value); 541 } 542 543 private NodeLiteralNode(final LiteralNode<Node> literalNode) { 544 super(literalNode); 545 } 546 547 @Override 548 protected Node copy(final CopyState cs) { 549 return new NodeLiteralNode(this); 550 } 551 552 @Override 553 public Node accept(final NodeVisitor visitor) { 554 if (visitor.enter(this) != null) { 555 if (value != null) { 556 value = value.accept(visitor); 557 } 558 return visitor.leave(this); 559 } 560 561 return this; 562 } 563 564 @Override 565 public Type getType() { 566 return value == null ? Type.OBJECT : super.getType(); 567 } 568 569 @Override 570 public Type getWidestOperationType() { 571 return value == null ? Type.OBJECT : value.getWidestOperationType(); 572 } 573 574 } 575 /** 576 * Create a new node literal for an arbitrary node 577 * 578 * @param source the source 579 * @param token token 580 * @param finish finish 581 * @param value the literal value node 582 * 583 * @return the new literal node 584 */ 585 public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish, final Node value) { 586 return new NodeLiteralNode(source, token, finish, value); 587 } 588 589 /** 590 * Create a new node literal based on a parent node (source, token, finish) 591 * 592 * @param parent parent node 593 * @param value node value 594 * 595 * @return the new literal node 596 */ 597 public static LiteralNode<?> newInstance(final Node parent, final Node value) { 598 return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 599 } 600 601 /** 602 * Array literal node class. 603 */ 604 public static class ArrayLiteralNode extends LiteralNode<Node[]> { 605 private static class PostsetMarker { 606 //empty 607 } 608 609 private static PostsetMarker POSTSET_MARKER = new PostsetMarker(); 610 611 /** Array element type. */ 612 private Type elementType; 613 614 /** Preset constant array. */ 615 private Object presets; 616 617 /** Indices of array elements requiring computed post sets. */ 618 private int[] postsets; 619 620 private List<ArrayUnit> units; 621 622 /** 623 * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can 624 * be split if they are too large, for bytecode generation reasons 625 */ 626 public static class ArrayUnit { 627 /** Compile unit associated with the postsets range. */ 628 private final CompileUnit compileUnit; 629 630 /** postsets range associated with the unit (hi not inclusive). */ 631 private final int lo, hi; 632 633 /** 634 * Constructor 635 * @param compileUnit compile unit 636 * @param lo lowest array index in unit 637 * @param hi highest array index in unit + 1 638 */ 639 public ArrayUnit(final CompileUnit compileUnit, final int lo, final int hi) { 640 this.compileUnit = compileUnit; 641 this.lo = lo; 642 this.hi = hi; 643 } 644 645 /** 646 * Get the high index position of the ArrayUnit (non inclusive) 647 * @return high index position 648 */ 649 public int getHi() { 650 return hi; 651 } 652 653 /** 654 * Get the low index position of the ArrayUnit (inclusive) 655 * @return low index position 656 */ 657 public int getLo() { 658 return lo; 659 } 660 661 /** 662 * The array compile unit 663 * @return array compile unit 664 */ 665 public CompileUnit getCompileUnit() { 666 return compileUnit; 667 } 668 } 669 670 /** 671 * Constructor 672 * 673 * @param source the source 674 * @param token token 675 * @param finish finish 676 * @param value array literal value, a Node array 677 */ 678 protected ArrayLiteralNode(final Source source, final long token, final int finish, final Node[] value) { 679 super(source, Token.recast(token, TokenType.ARRAY), finish, value); 680 this.elementType = Type.UNKNOWN; 681 } 682 683 /** 684 * Copy constructor 685 * @param node source array literal node 686 */ 687 protected ArrayLiteralNode(final ArrayLiteralNode node) { 688 super(node); 689 this.elementType = node.elementType; 690 } 691 692 @Override 693 protected Node copy(final CopyState cs) { 694 return new ArrayLiteralNode(this); 695 } 696 697 /** 698 * Compute things like widest element type needed. Internal use from compiler only 699 */ 700 public void analyze() { 701 elementType = Type.INT; 702 analyzeElements(); 703 704 if (elementType == Type.INT) { 705 presetIntArray(); 706 } else if (elementType.isNumeric()) { 707 presetNumberArray(); 708 } else { 709 presetObjectArray(); 710 } 711 } 712 713 private void presetIntArray() { 714 final int[] array = new int[value.length]; 715 final int[] computed = new int[value.length]; 716 int nComputed = 0; 717 718 for (int i = 0; i < value.length; i++) { 719 final Object element = objectAsConstant(value[i]); 720 721 if (element instanceof Number) { 722 array[i] = ((Number)element).intValue(); 723 } else { 724 computed[nComputed++] = i; 725 } 726 } 727 728 presets = array; 729 postsets = Arrays.copyOf(computed, nComputed); 730 } 731 732 private void presetNumberArray() { 733 final double[] array = new double[value.length]; 734 final int[] computed = new int[value.length]; 735 int nComputed = 0; 736 737 for (int i = 0; i < value.length; i++) { 738 final Object element = objectAsConstant(value[i]); 739 740 if (element instanceof Number) { 741 array[i] = ((Number)element).doubleValue(); 742 } else { 743 computed[nComputed++] = i; 744 } 745 } 746 747 presets = array; 748 postsets = Arrays.copyOf(computed, nComputed); 749 } 750 751 private void presetObjectArray() { 752 final Object[] array = new Object[value.length]; 753 final int[] computed = new int[value.length]; 754 int nComputed = 0; 755 756 for (int i = 0; i < value.length; i++) { 757 final Node node = value[i]; 758 759 if (node == null) { 760 computed[nComputed++] = i; 761 } else { 762 final Object element = objectAsConstant(node); 763 764 if (element != POSTSET_MARKER) { 765 array[i] = element; 766 } else { 767 computed[nComputed++] = i; 768 } 769 } 770 } 771 772 presets = array; 773 postsets = Arrays.copyOf(computed, nComputed); 774 } 775 776 private void analyzeElements() { 777 for (final Node node : value) { 778 if (node == null) { 779 elementType = elementType.widest(Type.OBJECT); //no way to represent undefined as number 780 break; 781 } 782 783 final Symbol symbol = node.getSymbol(); 784 assert symbol != null; //don't run this on unresolved nodes or you are in trouble 785 Type symbolType = symbol.getSymbolType(); 786 if (symbolType.isUnknown()) { 787 symbolType = Type.OBJECT; 788 } 789 790 if (symbolType.isBoolean()) { 791 elementType = elementType.widest(Type.OBJECT); 792 break; 793 } 794 795 elementType = elementType.widest(symbolType); 796 797 if (elementType.isObject()) { 798 break; 799 } 800 } 801 } 802 803 private Object objectAsConstant(final Object object) { 804 if (object == null) { 805 return null; 806 } else if (object instanceof Number || object instanceof String || object instanceof Boolean) { 807 return object; 808 } else if (object instanceof LiteralNode) { 809 return objectAsConstant(((LiteralNode<?>)object).getValue()); 810 } else if (object instanceof UnaryNode) { 811 final UnaryNode unaryNode = (UnaryNode)object; 812 813 if (unaryNode.isTokenType(TokenType.CONVERT) && unaryNode.getType().isObject()) { 814 return objectAsConstant(unaryNode.rhs()); 815 } 816 } 817 818 return POSTSET_MARKER; 819 } 820 821 @Override 822 public Node[] getArray() { 823 return value; 824 } 825 826 @Override 827 public Type getType() { 828 if (elementType.isInteger()) { 829 return Type.INT_ARRAY; 830 } else if (elementType.isNumeric()) { 831 return Type.NUMBER_ARRAY; 832 } else { 833 return Type.OBJECT_ARRAY; 834 } 835 } 836 837 /** 838 * Get the element type of this array literal 839 * @return element type 840 */ 841 public Type getElementType() { 842 return elementType; 843 } 844 845 /** 846 * Get indices of arrays containing computed post sets 847 * @return post set indices 848 */ 849 public int[] getPostsets() { 850 return postsets; 851 } 852 853 /** 854 * Get presets constant array 855 * @return presets array, always returns an array type 856 */ 857 public Object getPresets() { 858 return presets; 859 } 860 861 /** 862 * Get the array units that make up this ArrayLiteral 863 * @see ArrayUnit 864 * @return list of array units 865 */ 866 public List<ArrayUnit> getUnits() { 867 return units == null ? null : Collections.unmodifiableList(units); 868 } 869 870 /** 871 * Set the ArrayUnits that make up this ArrayLiteral 872 * @see ArrayUnit 873 * @param units list of array units 874 */ 875 public void setUnits(final List<ArrayUnit> units) { 876 this.units = units; 877 } 878 879 @Override 880 public Node accept(final NodeVisitor visitor) { 881 if (visitor.enter(this) != null) { 882 for (int i = 0; i < value.length; i++) { 883 final Node element = value[i]; 884 if (element != null) { 885 value[i] = element.accept(visitor); 886 } 887 } 888 return visitor.leave(this); 889 } 890 return this; 891 } 892 893 @Override 894 public void toString(final StringBuilder sb) { 895 sb.append('['); 896 boolean first = true; 897 for (final Node node : value) { 898 if (!first) { 899 sb.append(','); 900 sb.append(' '); 901 } 902 if (node == null) { 903 sb.append("undefined"); 904 } else { 905 node.toString(sb); 906 } 907 first = false; 908 } 909 sb.append(']'); 910 } 911 } 912 913 /** 914 * Create a new array literal of Nodes from a list of Node values 915 * 916 * @param source the source 917 * @param token token 918 * @param finish finish 919 * @param value literal value list 920 * 921 * @return the new literal node 922 */ 923 public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final List<Node> value) { 924 return new ArrayLiteralNode(source, token, finish, value.toArray(new Node[value.size()])); 925 } 926 927 928 /** 929 * Create a new array literal based on a parent node (source, token, finish) 930 * 931 * @param parent parent node 932 * @param value literal value list 933 * 934 * @return the new literal node 935 */ 936 public static LiteralNode<?> newInstance(final Node parent, final List<Node> value) { 937 return new ArrayLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()])); 938 } 939 940 /** 941 * Create a new array literal of Nodes 942 * 943 * @param source the source 944 * @param token token 945 * @param finish finish 946 * @param value literal value array 947 * 948 * @return the new literal node 949 */ 950 public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final Node[] value) { 951 return new ArrayLiteralNode(source, token, finish, value); 952 } 953 } --- EOF ---