forked from jasder/antlr
552 lines
16 KiB
C#
552 lines
16 KiB
C#
/*
|
|
* [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.Generic;
|
|
using System.Text;
|
|
using Antlr4.Runtime;
|
|
using Antlr4.Runtime.Atn;
|
|
using Antlr4.Runtime.Misc;
|
|
using Sharpen;
|
|
|
|
namespace Antlr4.Runtime.Atn
|
|
{
|
|
public abstract class PredictionContext
|
|
{
|
|
[NotNull]
|
|
public static readonly Antlr4.Runtime.Atn.PredictionContext EmptyLocal = EmptyPredictionContext
|
|
.LocalContext;
|
|
|
|
[NotNull]
|
|
public static readonly Antlr4.Runtime.Atn.PredictionContext EmptyFull = EmptyPredictionContext
|
|
.FullContext;
|
|
|
|
public const int EmptyLocalStateKey = int.MinValue;
|
|
|
|
public const int EmptyFullStateKey = int.MaxValue;
|
|
|
|
private const int InitialHash = 1;
|
|
|
|
private const int HashMultiplier = 31;
|
|
|
|
/// <summary>Stores the computed hash code of this PredictionContext.</summary>
|
|
/// <remarks>
|
|
/// Stores the computed hash code of this PredictionContext. The hash code is
|
|
/// computed in parts to match the following reference algorithm.
|
|
/// <pre>
|
|
/// private int referenceHashCode() {
|
|
/// int returnStateHashCode =
|
|
/// <see cref="InitialHash">INITIAL_HASH</see>
|
|
/// ;
|
|
/// for (int i = 0; i < size(); i++) {
|
|
/// returnStateHashCode = returnStateHashCode *
|
|
/// <see cref="HashMultiplier">HASH_MULTIPLIER</see>
|
|
/// ^ getReturnState(i);
|
|
/// }
|
|
/// int parentHashCode = INITIAL_HASH;
|
|
/// for (int i = 0; i < size(); i++) {
|
|
/// parentHashCode = parentHashCode * HASH_MULTIPLIER ^ getParent(i).hashCode();
|
|
/// }
|
|
/// int hashCode = INITIAL_HASH;
|
|
/// hashCode = hashCode * HASH_MULTIPLIER ^ parentHashCode;
|
|
/// hashCode = hashCode * HASH_MULTIPLIER ^ returnStateHashCode;
|
|
/// return hashCode;
|
|
/// }
|
|
/// </pre>
|
|
/// </remarks>
|
|
private readonly int cachedHashCode;
|
|
|
|
protected internal PredictionContext(int cachedHashCode)
|
|
{
|
|
this.cachedHashCode = cachedHashCode;
|
|
}
|
|
|
|
protected internal static int CalculateEmptyParentHashCode()
|
|
{
|
|
return InitialHash;
|
|
}
|
|
|
|
protected internal static int CalculateParentHashCode(Antlr4.Runtime.Atn.PredictionContext
|
|
parent)
|
|
{
|
|
return InitialHash * HashMultiplier ^ parent.GetHashCode();
|
|
}
|
|
|
|
protected internal static int CalculateParentHashCode(Antlr4.Runtime.Atn.PredictionContext
|
|
[] parents)
|
|
{
|
|
int hashCode = InitialHash;
|
|
foreach (Antlr4.Runtime.Atn.PredictionContext context in parents)
|
|
{
|
|
hashCode = hashCode * HashMultiplier ^ context.GetHashCode();
|
|
}
|
|
return hashCode;
|
|
}
|
|
|
|
protected internal static int CalculateEmptyReturnStateHashCode()
|
|
{
|
|
return InitialHash;
|
|
}
|
|
|
|
protected internal static int CalculateReturnStateHashCode(int returnState)
|
|
{
|
|
return InitialHash * HashMultiplier ^ returnState;
|
|
}
|
|
|
|
protected internal static int CalculateReturnStatesHashCode(int[] returnStates)
|
|
{
|
|
int hashCode = InitialHash;
|
|
foreach (int state in returnStates)
|
|
{
|
|
hashCode = hashCode * HashMultiplier ^ state;
|
|
}
|
|
return hashCode;
|
|
}
|
|
|
|
protected internal static int CalculateHashCode(int parentHashCode, int returnStateHashCode
|
|
)
|
|
{
|
|
return (InitialHash * HashMultiplier ^ parentHashCode) * HashMultiplier ^ returnStateHashCode;
|
|
}
|
|
|
|
public abstract int Size
|
|
{
|
|
get;
|
|
}
|
|
|
|
public abstract int GetReturnState(int index);
|
|
|
|
public abstract int FindReturnState(int returnState);
|
|
|
|
[NotNull]
|
|
public abstract Antlr4.Runtime.Atn.PredictionContext GetParent(int index);
|
|
|
|
protected internal abstract Antlr4.Runtime.Atn.PredictionContext AddEmptyContext(
|
|
);
|
|
|
|
protected internal abstract Antlr4.Runtime.Atn.PredictionContext RemoveEmptyContext
|
|
();
|
|
|
|
public static Antlr4.Runtime.Atn.PredictionContext FromRuleContext(ATN atn, RuleContext
|
|
outerContext)
|
|
{
|
|
return FromRuleContext(atn, outerContext, true);
|
|
}
|
|
|
|
public static Antlr4.Runtime.Atn.PredictionContext FromRuleContext(ATN atn, RuleContext
|
|
outerContext, bool fullContext)
|
|
{
|
|
if (outerContext.IsEmpty())
|
|
{
|
|
return fullContext ? EmptyFull : EmptyLocal;
|
|
}
|
|
Antlr4.Runtime.Atn.PredictionContext parent;
|
|
if (outerContext.parent != null)
|
|
{
|
|
parent = Antlr4.Runtime.Atn.PredictionContext.FromRuleContext(atn, outerContext.parent
|
|
, fullContext);
|
|
}
|
|
else
|
|
{
|
|
parent = fullContext ? EmptyFull : EmptyLocal;
|
|
}
|
|
ATNState state = atn.states[outerContext.invokingState];
|
|
RuleTransition transition = (RuleTransition)state.Transition(0);
|
|
return parent.GetChild(transition.followState.stateNumber);
|
|
}
|
|
|
|
private static Antlr4.Runtime.Atn.PredictionContext AddEmptyContext(Antlr4.Runtime.Atn.PredictionContext
|
|
context)
|
|
{
|
|
return context.AddEmptyContext();
|
|
}
|
|
|
|
private static Antlr4.Runtime.Atn.PredictionContext RemoveEmptyContext(Antlr4.Runtime.Atn.PredictionContext
|
|
context)
|
|
{
|
|
return context.RemoveEmptyContext();
|
|
}
|
|
|
|
public static Antlr4.Runtime.Atn.PredictionContext Join(Antlr4.Runtime.Atn.PredictionContext
|
|
context0, Antlr4.Runtime.Atn.PredictionContext context1)
|
|
{
|
|
return Join(context0, context1, PredictionContextCache.Uncached);
|
|
}
|
|
|
|
internal static Antlr4.Runtime.Atn.PredictionContext Join(Antlr4.Runtime.Atn.PredictionContext
|
|
context0, Antlr4.Runtime.Atn.PredictionContext context1, PredictionContextCache
|
|
contextCache)
|
|
{
|
|
if (context0 == context1)
|
|
{
|
|
return context0;
|
|
}
|
|
if (context0.IsEmpty)
|
|
{
|
|
return IsEmptyLocal(context0) ? context0 : AddEmptyContext(context1);
|
|
}
|
|
else
|
|
{
|
|
if (context1.IsEmpty)
|
|
{
|
|
return IsEmptyLocal(context1) ? context1 : AddEmptyContext(context0);
|
|
}
|
|
}
|
|
int context0size = context0.Size;
|
|
int context1size = context1.Size;
|
|
if (context0size == 1 && context1size == 1 && context0.GetReturnState(0) == context1
|
|
.GetReturnState(0))
|
|
{
|
|
Antlr4.Runtime.Atn.PredictionContext merged = contextCache.Join(context0.GetParent
|
|
(0), context1.GetParent(0));
|
|
if (merged == context0.GetParent(0))
|
|
{
|
|
return context0;
|
|
}
|
|
else
|
|
{
|
|
if (merged == context1.GetParent(0))
|
|
{
|
|
return context1;
|
|
}
|
|
else
|
|
{
|
|
return merged.GetChild(context0.GetReturnState(0));
|
|
}
|
|
}
|
|
}
|
|
int count = 0;
|
|
Antlr4.Runtime.Atn.PredictionContext[] parentsList = new Antlr4.Runtime.Atn.PredictionContext
|
|
[context0size + context1size];
|
|
int[] returnStatesList = new int[parentsList.Length];
|
|
int leftIndex = 0;
|
|
int rightIndex = 0;
|
|
bool canReturnLeft = true;
|
|
bool canReturnRight = true;
|
|
while (leftIndex < context0size && rightIndex < context1size)
|
|
{
|
|
if (context0.GetReturnState(leftIndex) == context1.GetReturnState(rightIndex))
|
|
{
|
|
parentsList[count] = contextCache.Join(context0.GetParent(leftIndex), context1.GetParent
|
|
(rightIndex));
|
|
returnStatesList[count] = context0.GetReturnState(leftIndex);
|
|
canReturnLeft = canReturnLeft && parentsList[count] == context0.GetParent(leftIndex
|
|
);
|
|
canReturnRight = canReturnRight && parentsList[count] == context1.GetParent(rightIndex
|
|
);
|
|
leftIndex++;
|
|
rightIndex++;
|
|
}
|
|
else
|
|
{
|
|
if (context0.GetReturnState(leftIndex) < context1.GetReturnState(rightIndex))
|
|
{
|
|
parentsList[count] = context0.GetParent(leftIndex);
|
|
returnStatesList[count] = context0.GetReturnState(leftIndex);
|
|
canReturnRight = false;
|
|
leftIndex++;
|
|
}
|
|
else
|
|
{
|
|
System.Diagnostics.Debug.Assert(context1.GetReturnState(rightIndex) < context0.GetReturnState
|
|
(leftIndex));
|
|
parentsList[count] = context1.GetParent(rightIndex);
|
|
returnStatesList[count] = context1.GetReturnState(rightIndex);
|
|
canReturnLeft = false;
|
|
rightIndex++;
|
|
}
|
|
}
|
|
count++;
|
|
}
|
|
while (leftIndex < context0size)
|
|
{
|
|
parentsList[count] = context0.GetParent(leftIndex);
|
|
returnStatesList[count] = context0.GetReturnState(leftIndex);
|
|
leftIndex++;
|
|
canReturnRight = false;
|
|
count++;
|
|
}
|
|
while (rightIndex < context1size)
|
|
{
|
|
parentsList[count] = context1.GetParent(rightIndex);
|
|
returnStatesList[count] = context1.GetReturnState(rightIndex);
|
|
rightIndex++;
|
|
canReturnLeft = false;
|
|
count++;
|
|
}
|
|
if (canReturnLeft)
|
|
{
|
|
return context0;
|
|
}
|
|
else
|
|
{
|
|
if (canReturnRight)
|
|
{
|
|
return context1;
|
|
}
|
|
}
|
|
if (count < parentsList.Length)
|
|
{
|
|
parentsList = Arrays.CopyOf(parentsList, count);
|
|
returnStatesList = Arrays.CopyOf(returnStatesList, count);
|
|
}
|
|
if (parentsList.Length == 0)
|
|
{
|
|
// if one of them was EMPTY_LOCAL, it would be empty and handled at the beginning of the method
|
|
return EmptyFull;
|
|
}
|
|
else
|
|
{
|
|
if (parentsList.Length == 1)
|
|
{
|
|
return new SingletonPredictionContext(parentsList[0], returnStatesList[0]);
|
|
}
|
|
else
|
|
{
|
|
return new ArrayPredictionContext(parentsList, returnStatesList);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool IsEmptyLocal(Antlr4.Runtime.Atn.PredictionContext context)
|
|
{
|
|
return context == EmptyLocal;
|
|
}
|
|
|
|
public static Antlr4.Runtime.Atn.PredictionContext GetCachedContext(Antlr4.Runtime.Atn.PredictionContext
|
|
context, IConcurrentMap<Antlr4.Runtime.Atn.PredictionContext, Antlr4.Runtime.Atn.PredictionContext
|
|
> contextCache, PredictionContext.IdentityHashMap visited)
|
|
{
|
|
if (context.IsEmpty)
|
|
{
|
|
return context;
|
|
}
|
|
Antlr4.Runtime.Atn.PredictionContext existing = visited.Get(context);
|
|
if (existing != null)
|
|
{
|
|
return existing;
|
|
}
|
|
existing = contextCache.Get(context);
|
|
if (existing != null)
|
|
{
|
|
visited.Put(context, existing);
|
|
return existing;
|
|
}
|
|
bool changed = false;
|
|
Antlr4.Runtime.Atn.PredictionContext[] parents = new Antlr4.Runtime.Atn.PredictionContext
|
|
[context.Size];
|
|
for (int i = 0; i < parents.Length; i++)
|
|
{
|
|
Antlr4.Runtime.Atn.PredictionContext parent = GetCachedContext(context.GetParent(
|
|
i), contextCache, visited);
|
|
if (changed || parent != context.GetParent(i))
|
|
{
|
|
if (!changed)
|
|
{
|
|
parents = new Antlr4.Runtime.Atn.PredictionContext[context.Size];
|
|
for (int j = 0; j < context.Size; j++)
|
|
{
|
|
parents[j] = context.GetParent(j);
|
|
}
|
|
changed = true;
|
|
}
|
|
parents[i] = parent;
|
|
}
|
|
}
|
|
if (!changed)
|
|
{
|
|
existing = contextCache.PutIfAbsent(context, context);
|
|
visited.Put(context, existing != null ? existing : context);
|
|
return context;
|
|
}
|
|
// We know parents.length>0 because context.isEmpty() is checked at the beginning of the method.
|
|
Antlr4.Runtime.Atn.PredictionContext updated;
|
|
if (parents.Length == 1)
|
|
{
|
|
updated = new SingletonPredictionContext(parents[0], context.GetReturnState(0));
|
|
}
|
|
else
|
|
{
|
|
ArrayPredictionContext arrayPredictionContext = (ArrayPredictionContext)context;
|
|
updated = new ArrayPredictionContext(parents, arrayPredictionContext.returnStates
|
|
, context.cachedHashCode);
|
|
}
|
|
existing = contextCache.PutIfAbsent(updated, updated);
|
|
visited.Put(updated, existing != null ? existing : updated);
|
|
visited.Put(context, existing != null ? existing : updated);
|
|
return updated;
|
|
}
|
|
|
|
public virtual Antlr4.Runtime.Atn.PredictionContext AppendContext(int returnContext
|
|
, PredictionContextCache contextCache)
|
|
{
|
|
return AppendContext(Antlr4.Runtime.Atn.PredictionContext.EmptyFull.GetChild(returnContext
|
|
), contextCache);
|
|
}
|
|
|
|
public abstract Antlr4.Runtime.Atn.PredictionContext AppendContext(Antlr4.Runtime.Atn.PredictionContext
|
|
suffix, PredictionContextCache contextCache);
|
|
|
|
public virtual Antlr4.Runtime.Atn.PredictionContext GetChild(int returnState)
|
|
{
|
|
return new SingletonPredictionContext(this, returnState);
|
|
}
|
|
|
|
public abstract bool IsEmpty
|
|
{
|
|
get;
|
|
}
|
|
|
|
public abstract bool HasEmpty
|
|
{
|
|
get;
|
|
}
|
|
|
|
public sealed override int GetHashCode()
|
|
{
|
|
return cachedHashCode;
|
|
}
|
|
|
|
public abstract override bool Equals(object o);
|
|
|
|
//@Override
|
|
//public String toString() {
|
|
// return toString(null, Integer.MAX_VALUE);
|
|
//}
|
|
public virtual string[] ToStrings<_T0>(Recognizer<_T0> recognizer, int currentState
|
|
)
|
|
{
|
|
return ToStrings(recognizer, Antlr4.Runtime.Atn.PredictionContext.EmptyFull, currentState
|
|
);
|
|
}
|
|
|
|
public virtual string[] ToStrings<_T0>(Recognizer<_T0> recognizer, Antlr4.Runtime.Atn.PredictionContext
|
|
stop, int currentState)
|
|
{
|
|
IList<string> result = new List<string>();
|
|
for (int perm = 0; ; perm++)
|
|
{
|
|
int offset = 0;
|
|
bool last = true;
|
|
Antlr4.Runtime.Atn.PredictionContext p = this;
|
|
int stateNumber = currentState;
|
|
StringBuilder localBuffer = new StringBuilder();
|
|
localBuffer.Append("[");
|
|
while (!p.IsEmpty && p != stop)
|
|
{
|
|
int index = 0;
|
|
if (p.Size > 0)
|
|
{
|
|
int bits = 1;
|
|
while ((1 << bits) < p.Size)
|
|
{
|
|
bits++;
|
|
}
|
|
int mask = (1 << bits) - 1;
|
|
index = (perm >> offset) & mask;
|
|
last &= index >= p.Size - 1;
|
|
if (index >= p.Size)
|
|
{
|
|
goto outer_continue;
|
|
}
|
|
offset += bits;
|
|
}
|
|
if (recognizer != null)
|
|
{
|
|
if (localBuffer.Length > 1)
|
|
{
|
|
// first char is '[', if more than that this isn't the first rule
|
|
localBuffer.Append(' ');
|
|
}
|
|
ATN atn = recognizer.GetATN();
|
|
ATNState s = atn.states[stateNumber];
|
|
string ruleName = recognizer.GetRuleNames()[s.ruleIndex];
|
|
localBuffer.Append(ruleName);
|
|
}
|
|
else
|
|
{
|
|
if (p.GetReturnState(index) != EmptyFullStateKey)
|
|
{
|
|
if (!p.IsEmpty)
|
|
{
|
|
if (localBuffer.Length > 1)
|
|
{
|
|
// first char is '[', if more than that this isn't the first rule
|
|
localBuffer.Append(' ');
|
|
}
|
|
localBuffer.Append(p.GetReturnState(index));
|
|
}
|
|
}
|
|
}
|
|
stateNumber = p.GetReturnState(index);
|
|
p = p.GetParent(index);
|
|
}
|
|
localBuffer.Append("]");
|
|
result.AddItem(localBuffer.ToString());
|
|
if (last)
|
|
{
|
|
break;
|
|
}
|
|
outer_continue: ;
|
|
}
|
|
outer_break: ;
|
|
return Sharpen.Collections.ToArray(result, new string[result.Count]);
|
|
}
|
|
|
|
public sealed class IdentityHashMap : FlexibleHashMap<PredictionContext, PredictionContext
|
|
>
|
|
{
|
|
public IdentityHashMap() : base(PredictionContext.IdentityEqualityComparator.Instance
|
|
)
|
|
{
|
|
}
|
|
}
|
|
|
|
public sealed class IdentityEqualityComparator : AbstractEqualityComparator<PredictionContext
|
|
>
|
|
{
|
|
public static readonly PredictionContext.IdentityEqualityComparator Instance = new
|
|
PredictionContext.IdentityEqualityComparator();
|
|
|
|
public IdentityEqualityComparator()
|
|
{
|
|
}
|
|
|
|
public override int HashCode(PredictionContext obj)
|
|
{
|
|
return obj.GetHashCode();
|
|
}
|
|
|
|
public override bool Equals(PredictionContext a, PredictionContext b)
|
|
{
|
|
return a == b;
|
|
}
|
|
}
|
|
}
|
|
}
|