diff --git a/Antlr4.Runtime/Antlr4.Runtime.csproj b/Antlr4.Runtime/Antlr4.Runtime.csproj index 4ca17afb7..ca275e5f9 100644 --- a/Antlr4.Runtime/Antlr4.Runtime.csproj +++ b/Antlr4.Runtime/Antlr4.Runtime.csproj @@ -70,6 +70,7 @@ + diff --git a/Antlr4.Runtime/Atn/PredictionMode.cs b/Antlr4.Runtime/Atn/PredictionMode.cs new file mode 100644 index 000000000..907238594 --- /dev/null +++ b/Antlr4.Runtime/Atn/PredictionMode.cs @@ -0,0 +1,911 @@ +/* + * [The "BSD license"] + * Copyright (c) 2013 Terence Parr + * Copyright (c) 2013 Sam Harwell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System.Collections; +using System.Collections.Generic; +using Antlr4.Runtime.Atn; +using Antlr4.Runtime.Misc; +using Sharpen; + +namespace Antlr4.Runtime.Atn +{ + [System.Serializable] + public sealed class PredictionMode + { + /// + /// Do only local context prediction (SLL style) and using + /// heuristic which almost always works but is much faster + /// than precise answer. + /// + /// + /// Do only local context prediction (SLL style) and using + /// heuristic which almost always works but is much faster + /// than precise answer. + /// + internal static readonly PredictionMode Sll = new PredictionMode(); + + /// Full LL(*) that always gets right answer. + /// + /// Full LL(*) that always gets right answer. For speed + /// reasons, we terminate the prediction process when we know for + /// sure which alt to predict. We don't always know what + /// the ambiguity is in this mode. + /// + internal static readonly PredictionMode Ll = new PredictionMode(); + + /// + /// Tell the full LL prediction algorithm to pursue lookahead until + /// it has uniquely predicted an alternative without conflict or it's + /// certain that it's found an ambiguous input sequence. + /// + /// + /// Tell the full LL prediction algorithm to pursue lookahead until + /// it has uniquely predicted an alternative without conflict or it's + /// certain that it's found an ambiguous input sequence. when this + /// variable is false. When true, the prediction process will + /// continue looking for the exact ambiguous sequence even if + /// it has already figured out which alternative to predict. + /// + internal static readonly PredictionMode LlExactAmbigDetection = new PredictionMode + (); + + /// A Map that uses just the state and the stack context as the key. + /// A Map that uses just the state and the stack context as the key. + internal class AltAndContextMap : FlexibleHashMap + { + public AltAndContextMap() : base(PredictionMode.AltAndContextConfigEqualityComparator + .Instance) + { + } + } + + private sealed class AltAndContextConfigEqualityComparator : AbstractEqualityComparator + + { + public static readonly PredictionMode.AltAndContextConfigEqualityComparator Instance + = new PredictionMode.AltAndContextConfigEqualityComparator(); + + public AltAndContextConfigEqualityComparator() + { + } + + /// Code is function of (s, _, ctx, _) + public override int HashCode(ATNConfig o) + { + int hashCode = 7; + hashCode = 31 * hashCode + o.GetState().stateNumber; + hashCode = 31 * hashCode + o.GetContext().GetHashCode(); + return hashCode; + } + + public override bool Equals(ATNConfig a, ATNConfig b) + { + if (a == b) + { + return true; + } + if (a == null || b == null) + { + return false; + } + if (HashCode(a) != HashCode(b)) + { + return false; + } + return a.GetState().stateNumber == b.GetState().stateNumber && a.GetContext().Equals + (b.GetContext()); + } + } + + /// Computes the SLL prediction termination condition. + /// + /// Computes the SLL prediction termination condition. + ///

+ /// This method computes the SLL prediction termination condition for both of + /// the following cases. + ///

    + ///
  • The usual SLL+LL fallback upon SLL conflict
  • + ///
  • Pure SLL without LL fallback
  • + ///
+ ///

+ /// COMBINED SLL+LL PARSING + ///

+ /// When LL-fallback is enabled upon SLL conflict, correct predictions are + /// ensured regardless of how the termination condition is computed by this + /// method. Due to the substantially higher cost of LL prediction, the + /// prediction should only fall back to LL when the additional lookahead + /// cannot lead to a unique SLL prediction. + ///

+ /// Assuming combined SLL+LL parsing, an SLL configuration set with only + /// conflicting subsets should fall back to full LL, even if the + /// configuration sets don't resolve to the same alternative (e.g. + /// + /// + /// 1,2}} and + /// + /// + /// 3,4}}. If there is at least one non-conflicting + /// configuration, SLL could continue with the hopes that more lookahead will + /// resolve via one of those non-conflicting configurations. + ///

+ /// Here's the prediction termination rule them: SLL (for SLL+LL parsing) + /// stops when it sees only conflicting configuration subsets. In contrast, + /// full LL keeps going when there is uncertainty. + ///

+ /// HEURISTIC + ///

+ /// As a heuristic, we stop prediction when we see any conflicting subset + /// unless we see a state that only has one alternative associated with it. + /// The single-alt-state thing lets prediction continue upon rules like + /// (otherwise, it would admit defeat too soon): + ///

+ /// [12|1|[], 6|2|[], 12|2|[]]. s : (ID | ID ID?) ';' ; + ///

+ /// When the ATN simulation reaches the state before + /// ';' + /// , it has a + /// DFA state that looks like: + /// [12|1|[], 6|2|[], 12|2|[]] + /// . Naturally + /// 12|1|[] + /// and + /// 12|2|[] + /// conflict, but we cannot stop + /// processing this node because alternative to has another way to continue, + /// via + /// [6|2|[]] + /// . + ///

+ /// It also let's us continue for this rule: + ///

+ /// [1|1|[], 1|2|[], 8|3|[]] a : A | A | A B ; + ///

+ /// After matching input A, we reach the stop state for rule A, state 1. + /// State 8 is the state right before B. Clearly alternatives 1 and 2 + /// conflict and no amount of further lookahead will separate the two. + /// However, alternative 3 will be able to continue and so we do not stop + /// working on this state. In the previous example, we're concerned with + /// states associated with the conflicting alternatives. Here alt 3 is not + /// associated with the conflicting configs, but since we can continue + /// looking for input reasonably, don't declare the state done. + ///

+ /// PURE SLL PARSING + ///

+ /// To handle pure SLL parsing, all we have to do is make sure that we + /// combine stack contexts for configurations that differ only by semantic + /// predicate. From there, we can do the usual SLL termination heuristic. + ///

+ /// PREDICATES IN SLL+LL PARSING + ///

+ /// SLL decisions don't evaluate predicates until after they reach DFA stop + /// states because they need to create the DFA cache that works in all + /// semantic situations. In contrast, full LL evaluates predicates collected + /// during start state computation so it can ignore predicates thereafter. + /// This means that SLL termination detection can totally ignore semantic + /// predicates. + ///

+ /// Implementation-wise, + /// ATNConfigSet + /// combines stack contexts but not + /// semantic predicate contexts so we might see two configurations like the + /// following. + ///

+ /// + /// (s, 1, x, + /// ), (s, 1, x', {p})} + ///

+ /// Before testing these configurations against others, we have to merge + /// x + /// and + /// x' + /// (without modifying the existing configurations). + /// For example, we test + /// (x+x')==x'' + /// when looking for conflicts in + /// the following configurations. + ///

+ /// + /// (s, 1, x, + /// ), (s, 1, x', {p}), (s, 2, x'', {})} + ///

+ /// If the configuration set has predicates (as indicated by + /// ATNConfigSet.HasSemanticContext() + /// ), this algorithm makes a copy of + /// the configurations to strip out all of the predicates so that a standard + /// ATNConfigSet + /// will merge everything ignoring predicates. + /// + public static bool HasSLLConflictTerminatingPrediction(PredictionMode mode, ATNConfigSet + configs) + { + if (AllConfigsInRuleStopStates(configs)) + { + return true; + } + // pure SLL mode parsing + if (mode == PredictionMode.Sll) + { + // Don't bother with combining configs from different semantic + // contexts if we can fail over to full LL; costs more time + // since we'll often fail over anyway. + if (configs.HasSemanticContext()) + { + // dup configs, tossing out semantic predicates + ATNConfigSet dup = new ATNConfigSet(); + foreach (ATNConfig c in configs) + { + c = c.Transform(c.GetState(), SemanticContext.None); + dup.AddItem(c); + } + configs = dup; + } + } + // now we have combined contexts for configs with dissimilar preds + // pure SLL or combined SLL+LL mode parsing + ICollection altsets = GetConflictingAltSubsets(configs); + bool heuristic = HasConflictingAltSet(altsets) && !HasStateAssociatedWithOneAlt(configs + ); + return heuristic; + } + + ///

+ /// Checks if any configuration in + /// configs + /// is in a + /// RuleStopState + /// . Configurations meeting this condition have reached + /// the end of the decision rule (local context) or end of start rule (full + /// context). + /// + /// the configuration set to test + /// + /// + /// true + /// if any configuration in + /// configs + /// is in a + /// RuleStopState + /// , otherwise + /// false + /// + public static bool HasConfigInRuleStopState(ATNConfigSet configs) + { + foreach (ATNConfig c in configs) + { + if (c.GetState() is RuleStopState) + { + return true; + } + } + return false; + } + + /// + /// Checks if all configurations in + /// configs + /// are in a + /// RuleStopState + /// . Configurations meeting this condition have reached + /// the end of the decision rule (local context) or end of start rule (full + /// context). + /// + /// the configuration set to test + /// + /// + /// true + /// if all configurations in + /// configs + /// are in a + /// RuleStopState + /// , otherwise + /// false + /// + public static bool AllConfigsInRuleStopStates(ATNConfigSet configs) + { + foreach (ATNConfig config in configs) + { + if (!(config.GetState() is RuleStopState)) + { + return false; + } + } + return true; + } + + /// Full LL prediction termination. + /// + /// Full LL prediction termination. + ///

+ /// Can we stop looking ahead during ATN simulation or is there some + /// uncertainty as to which alternative we will ultimately pick, after + /// consuming more input? Even if there are partial conflicts, we might know + /// that everything is going to resolve to the same minimum alternative. That + /// means we can stop since no more lookahead will change that fact. On the + /// other hand, there might be multiple conflicts that resolve to different + /// minimums. That means we need more look ahead to decide which of those + /// alternatives we should predict. + ///

+ /// The basic idea is to split the set of configurations + /// C + /// , into + /// conflicting subsets + /// (s, _, ctx, _) + /// and singleton subsets with + /// non-conflicting configurations. Two configurations conflict if they have + /// identical + /// ATNConfig#state + /// and + /// ATNConfig#context + /// values + /// but different + /// ATNConfig.GetAlt() + /// value, e.g. + /// (s, i, ctx, _) + /// and + /// (s, j, ctx, _) + /// for + /// i!=j + /// . + ///

+ /// Reduce these configuration subsets to the set of possible alternatives. + /// You can compute the alternative subsets in one pass as follows: + ///

+ /// + /// A_s,ctx = + /// i | (s, i, ctx, _)}} for each configuration in + /// C + /// holding + /// s + /// and + /// ctx + /// fixed. + ///

+ /// Or in pseudo-code, for each configuration + /// c + /// in + /// C + /// : + ///

+        /// map[c] U= c.
+        /// getAlt()
+        /// # map hash/equals uses s and x, not
+        /// alt and not pred
+        /// 
+ ///

+ /// The values in + /// map + /// are the set of + /// A_s,ctx + /// sets. + ///

+ /// If + /// |A_s,ctx|=1 + /// then there is no conflict associated with + /// s + /// and + /// ctx + /// . + ///

+ /// Reduce the subsets to singletons by choosing a minimum of each subset. If + /// the union of these alternative subsets is a singleton, then no amount of + /// more lookahead will help us. We will always pick that alternative. If, + /// however, there is more than one alternative, then we are uncertain which + /// alternative to predict and must continue looking for resolution. We may + /// or may not discover an ambiguity in the future, even if there are no + /// conflicting subsets this round. + ///

+ /// The biggest sin is to terminate early because it means we've made a + /// decision but were uncertain as to the eventual outcome. We haven't used + /// enough lookahead. On the other hand, announcing a conflict too late is no + /// big deal; you will still have the conflict. It's just inefficient. It + /// might even look until the end of file. + ///

+ /// No special consideration for semantic predicates is required because + /// predicates are evaluated on-the-fly for full LL prediction, ensuring that + /// no configuration contains a semantic context during the termination + /// check. + ///

+ /// CONFLICTING CONFIGS + ///

+ /// Two configurations + /// (s, i, x) + /// and + /// (s, j, x') + /// , conflict + /// when + /// i!=j + /// but + /// x=x' + /// . Because we merge all + /// (s, i, _) + /// configurations together, that means that there are at + /// most + /// n + /// configurations associated with state + /// s + /// for + /// n + /// possible alternatives in the decision. The merged stacks + /// complicate the comparison of configuration contexts + /// x + /// and + /// x' + /// . Sam checks to see if one is a subset of the other by calling + /// merge and checking to see if the merged result is either + /// x + /// or + /// x' + /// . If the + /// x + /// associated with lowest alternative + /// i + /// is the superset, then + /// i + /// is the only possible prediction since the + /// others resolve to + /// min(i) + /// as well. However, if + /// x + /// is + /// associated with + /// j>i + /// then at least one stack configuration for + /// j + /// is not in conflict with alternative + /// i + /// . The algorithm + /// should keep going, looking for more lookahead due to the uncertainty. + ///

+ /// For simplicity, I'm doing a equality check between + /// x + /// and + /// x' + /// that lets the algorithm continue to consume lookahead longer + /// than necessary. The reason I like the equality is of course the + /// simplicity but also because that is the test you need to detect the + /// alternatives that are actually in conflict. + ///

+ /// CONTINUE/STOP RULE + ///

+ /// Continue if union of resolved alternative sets from non-conflicting and + /// conflicting alternative subsets has more than one alternative. We are + /// uncertain about which alternative to predict. + ///

+ /// The complete set of alternatives, + /// [i for (_,i,_)] + /// , tells us which + /// alternatives are still in the running for the amount of input we've + /// consumed at this point. The conflicting sets let us to strip away + /// configurations that won't lead to more states because we resolve + /// conflicts to the configuration with a minimum alternate for the + /// conflicting set. + ///

+ /// CASES + ///

    + ///
  • no conflicts and more than 1 alternative in set => continue
  • + ///
  • + /// (s, 1, x) + /// , + /// (s, 2, x) + /// , + /// (s, 3, z) + /// , + /// (s', 1, y) + /// , + /// (s', 2, y) + /// yields non-conflicting set + /// + /// + /// 3}} U conflicting sets + /// + /// min( + /// 1,2})} U + /// + /// min( + /// 1,2})} = + /// + /// + /// 1,3}} => continue + ///
  • + ///
  • + /// (s, 1, x) + /// , + /// (s, 2, x) + /// , + /// (s', 1, y) + /// , + /// (s', 2, y) + /// , + /// (s'', 1, z) + /// yields non-conflicting set + /// + /// + /// 1}} U conflicting sets + /// + /// min( + /// 1,2})} U + /// + /// min( + /// 1,2})} = + /// + /// + /// 1}} => stop and predict 1
  • + ///
  • + /// (s, 1, x) + /// , + /// (s, 2, x) + /// , + /// (s', 1, y) + /// , + /// (s', 2, y) + /// yields conflicting, reduced sets + /// + /// + /// 1}} U + /// + /// + /// 1}} = + /// + /// + /// 1}} => stop and predict 1, can announce + /// ambiguity + /// + /// + /// 1,2}}
  • + ///
  • + /// (s, 1, x) + /// , + /// (s, 2, x) + /// , + /// (s', 2, y) + /// , + /// (s', 3, y) + /// yields conflicting, reduced sets + /// + /// + /// 1}} U + /// + /// + /// 2}} = + /// + /// + /// 1,2}} => continue
  • + ///
  • + /// (s, 1, x) + /// , + /// (s, 2, x) + /// , + /// (s', 3, y) + /// , + /// (s', 4, y) + /// yields conflicting, reduced sets + /// + /// + /// 1}} U + /// + /// + /// 3}} = + /// + /// + /// 1,3}} => continue
  • + ///
+ /// EXACT AMBIGUITY DETECTION + ///

+ /// If all states report the same conflicting set of alternatives, then we + /// know we have the exact ambiguity set. + ///

+ /// |A_i|>1 and + /// A_i = A_j for all i, j. + ///

+ /// In other words, we continue examining lookahead until all + /// A_i + /// have more than one alternative and all + /// A_i + /// are the same. If + /// + /// A= + /// {1,2}, {1,3}}}, then regular LL prediction would terminate + /// because the resolved set is + /// + /// + /// 1}}. To determine what the real + /// ambiguity is, we have to know whether the ambiguity is between one and + /// two or one and three so we keep going. We can only stop prediction when + /// we need exact ambiguity detection when the sets look like + /// + /// A= + /// {1,2}}} or + /// + /// + /// {1,2},{1,2}}}, etc... + /// + public static int ResolvesToJustOneViableAlt(ICollection altsets) + { + return GetSingleViableAlt(altsets); + } + + ///

+ /// Determines if every alternative subset in + /// altsets + /// contains more + /// than one alternative. + /// + /// a collection of alternative subsets + /// + /// + /// true + /// if every + /// System.Collections.BitArray + /// in + /// altsets + /// has + /// cardinality + /// > 1, otherwise + /// false + /// + public static bool AllSubsetsConflict(ICollection altsets) + { + return !HasNonConflictingAltSet(altsets); + } + + /// + /// Determines if any single alternative subset in + /// altsets + /// contains + /// exactly one alternative. + /// + /// a collection of alternative subsets + /// + /// + /// true + /// if + /// altsets + /// contains a + /// System.Collections.BitArray + /// with + /// cardinality + /// 1, otherwise + /// false + /// + public static bool HasNonConflictingAltSet(ICollection altsets) + { + foreach (BitArray alts in altsets) + { + if (alts.Cardinality() == 1) + { + return true; + } + } + return false; + } + + /// + /// Determines if any single alternative subset in + /// altsets + /// contains + /// more than one alternative. + /// + /// a collection of alternative subsets + /// + /// + /// true + /// if + /// altsets + /// contains a + /// System.Collections.BitArray + /// with + /// cardinality + /// > 1, otherwise + /// false + /// + public static bool HasConflictingAltSet(ICollection altsets) + { + foreach (BitArray alts in altsets) + { + if (alts.Cardinality() > 1) + { + return true; + } + } + return false; + } + + /// + /// Determines if every alternative subset in + /// altsets + /// is equivalent. + /// + /// a collection of alternative subsets + /// + /// + /// true + /// if every member of + /// altsets + /// is equal to the + /// others, otherwise + /// false + /// + public static bool AllSubsetsEqual(ICollection altsets) + { + IEnumerator it = altsets.GetEnumerator(); + BitArray first = it.Next(); + while (it.HasNext()) + { + BitArray next = it.Next(); + if (!next.Equals(first)) + { + return false; + } + } + return true; + } + + /// + /// Returns the unique alternative predicted by all alternative subsets in + /// altsets + /// . If no such alternative exists, this method returns + /// ATN.InvalidAltNumber + /// . + /// + /// a collection of alternative subsets + public static int GetUniqueAlt(ICollection altsets) + { + BitArray all = GetAlts(altsets); + if (all.Cardinality() == 1) + { + return all.NextSetBit(0); + } + return ATN.InvalidAltNumber; + } + + /// + /// Gets the complete set of represented alternatives for a collection of + /// alternative subsets. + /// + /// + /// Gets the complete set of represented alternatives for a collection of + /// alternative subsets. This method returns the union of each + /// System.Collections.BitArray + /// in + /// altsets + /// . + /// + /// a collection of alternative subsets + /// + /// the set of represented alternatives in + /// altsets + /// + public static BitArray GetAlts(ICollection altsets) + { + BitArray all = new BitArray(); + foreach (BitArray alts in altsets) + { + all.Or(alts); + } + return all; + } + + /// This function gets the conflicting alt subsets from a configuration set. + /// + /// + /// This function gets the conflicting alt subsets from a configuration set. + /// For each configuration + /// c + /// in + /// configs + /// : + ///
+        /// map[c] U= c.
+        /// getAlt()
+        /// # map hash/equals uses s and x, not
+        /// alt and not pred
+        /// 
+ ///
+ [NotNull] + public static ICollection GetConflictingAltSubsets(ATNConfigSet configs + ) + { + PredictionMode.AltAndContextMap configToAlts = new PredictionMode.AltAndContextMap + (); + foreach (ATNConfig c in configs) + { + BitArray alts = configToAlts.Get(c); + if (alts == null) + { + alts = new BitArray(); + configToAlts.Put(c, alts); + } + alts.Set(c.GetAlt()); + } + return configToAlts.Values; + } + + /// Get a map from state to alt subset from a configuration set. + /// + /// Get a map from state to alt subset from a configuration set. For each + /// configuration + /// c + /// in + /// configs + /// : + ///
+        /// map[c.
+        /// state
+        /// ] U= c.
+        /// getAlt()
+        /// 
+ ///
+ [NotNull] + public static IDictionary GetStateToAltMap(ATNConfigSet configs + ) + { + IDictionary m = new Dictionary(); + foreach (ATNConfig c in configs) + { + BitArray alts = m.Get(c.GetState()); + if (alts == null) + { + alts = new BitArray(); + m.Put(c.GetState(), alts); + } + alts.Set(c.GetAlt()); + } + return m; + } + + public static bool HasStateAssociatedWithOneAlt(ATNConfigSet configs) + { + IDictionary x = GetStateToAltMap(configs); + foreach (BitArray alts in x.Values) + { + if (alts.Cardinality() == 1) + { + return true; + } + } + return false; + } + + public static int GetSingleViableAlt(ICollection altsets) + { + BitArray viableAlts = new BitArray(); + foreach (BitArray alts in altsets) + { + int minAlt = alts.NextSetBit(0); + viableAlts.Set(minAlt); + if (viableAlts.Cardinality() > 1) + { + // more than 1 viable alt + return ATN.InvalidAltNumber; + } + } + return viableAlts.NextSetBit(0); + } + } +} diff --git a/reference/sharpen b/reference/sharpen index f14a6feae..60b41b329 160000 --- a/reference/sharpen +++ b/reference/sharpen @@ -1 +1 @@ -Subproject commit f14a6feaed23300e61e95b09756cd2295c1e2636 +Subproject commit 60b41b32982f35792e379f71364e61a0db4db658 diff --git a/reference/sharpen-all-options.txt b/reference/sharpen-all-options.txt index 83c009daf..5bea99aa8 100644 --- a/reference/sharpen-all-options.txt +++ b/reference/sharpen-all-options.txt @@ -11,8 +11,8 @@ -methodMapping java.util.Iterator.hasNext HasNext -methodMapping java.util.Iterator.next Next --typeMapping java.util.Comparator System.Collections.IEnumerator --typeMapping java.util.ArrayList System.Collections.ArrayList +-typeMapping java.util.Comparator System.Collections.IComparer +-typeMapping java.util.ArrayList System.Collections.ArrayList -methodMapping java.util.List.addAll AddRange -methodMapping java.util.AbstractList.addAll AddRange