antlr/Antlr4.Runtime/Atn/SemanticContext.cs

420 lines
14 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 Antlr4.Runtime;
using Antlr4.Runtime.Atn;
using Antlr4.Runtime.Misc;
using Sharpen;
namespace Antlr4.Runtime.Atn
{
/// <summary>
/// A tree structure used to record the semantic context in which
/// an ATN configuration is valid.
/// </summary>
/// <remarks>
/// A tree structure used to record the semantic context in which
/// an ATN configuration is valid. It's either a single predicate,
/// a conjunction
/// <code>p1&&p2</code>
/// , or a sum of products
/// <code>p1||p2</code>
/// .
/// <p/>
/// I have scoped the
/// <see cref="AND">AND</see>
/// ,
/// <see cref="OR">OR</see>
/// , and
/// <see cref="Predicate">Predicate</see>
/// subclasses of
/// <see cref="SemanticContext">SemanticContext</see>
/// within the scope of this outer class.
/// </remarks>
public abstract class SemanticContext
{
public static readonly SemanticContext None = new SemanticContext.Predicate();
public SemanticContext parent;
/// <summary>
/// For context independent predicates, we evaluate them without a local
/// context (i.e., null context).
/// </summary>
/// <remarks>
/// For context independent predicates, we evaluate them without a local
/// context (i.e., null context). That way, we can evaluate them without
/// having to create proper rule-specific context during prediction (as
/// opposed to the parser, which creates them naturally). In a practical
/// sense, this avoids a cast exception from RuleContext to myruleContext.
/// <p/>
/// For context dependent predicates, we must pass in a local context so that
/// references such as $arg evaluate properly as _localctx.arg. We only
/// capture context dependent predicates in the context in which we begin
/// prediction, so we passed in the outer context here in case of context
/// dependent predicate evaluation.
/// </remarks>
public abstract bool Eval<_T0>(Recognizer<_T0> parser, RuleContext outerContext);
public class Predicate : SemanticContext
{
public readonly int ruleIndex;
public readonly int predIndex;
public readonly bool isCtxDependent;
public Predicate()
{
// e.g., $i ref in pred
this.ruleIndex = -1;
this.predIndex = -1;
this.isCtxDependent = false;
}
public Predicate(int ruleIndex, int predIndex, bool isCtxDependent)
{
this.ruleIndex = ruleIndex;
this.predIndex = predIndex;
this.isCtxDependent = isCtxDependent;
}
public override bool Eval<_T0>(Recognizer<_T0> parser, RuleContext outerContext)
{
RuleContext localctx = isCtxDependent ? outerContext : null;
return parser.Sempred(localctx, ruleIndex, predIndex);
}
public override int GetHashCode()
{
int hashCode = 1;
hashCode = 31 * hashCode + ruleIndex;
hashCode = 31 * hashCode + predIndex;
hashCode = 31 * hashCode + (isCtxDependent ? 1 : 0);
return hashCode;
}
public override bool Equals(object obj)
{
if (!(obj is SemanticContext.Predicate))
{
return false;
}
if (this == obj)
{
return true;
}
SemanticContext.Predicate p = (SemanticContext.Predicate)obj;
return this.ruleIndex == p.ruleIndex && this.predIndex == p.predIndex && this.isCtxDependent
== p.isCtxDependent;
}
public override string ToString()
{
return "{" + ruleIndex + ":" + predIndex + "}?";
}
}
public class PrecedencePredicate : SemanticContext, IComparable<SemanticContext.PrecedencePredicate
>
{
public readonly int precedence;
public PrecedencePredicate()
{
this.precedence = 0;
}
public PrecedencePredicate(int precedence)
{
this.precedence = precedence;
}
public override bool Eval<_T0>(Recognizer<_T0> parser, RuleContext outerContext)
{
return parser.Precpred(outerContext, precedence);
}
public virtual int CompareTo(SemanticContext.PrecedencePredicate o)
{
return precedence - o.precedence;
}
public override int GetHashCode()
{
int hashCode = 1;
hashCode = 31 * hashCode + precedence;
return hashCode;
}
public override bool Equals(object obj)
{
if (!(obj is SemanticContext.PrecedencePredicate))
{
return false;
}
if (this == obj)
{
return true;
}
SemanticContext.PrecedencePredicate other = (SemanticContext.PrecedencePredicate)
obj;
return this.precedence == other.precedence;
}
public override string ToString()
{
return base.ToString();
}
}
public class AND : SemanticContext
{
[NotNull]
public readonly SemanticContext[] opnds;
public AND(SemanticContext a, SemanticContext b)
{
ICollection<SemanticContext> operands = new HashSet<SemanticContext>();
if (a is SemanticContext.AND)
{
Sharpen.Collections.AddAll(operands, Arrays.AsList(((SemanticContext.AND)a).opnds
));
}
else
{
operands.AddItem(a);
}
if (b is SemanticContext.AND)
{
Sharpen.Collections.AddAll(operands, Arrays.AsList(((SemanticContext.AND)b).opnds
));
}
else
{
operands.AddItem(b);
}
IList<SemanticContext.PrecedencePredicate> precedencePredicates = FilterPrecedencePredicates
(operands);
if (!precedencePredicates.IsEmpty())
{
// interested in the transition with the lowest precedence
SemanticContext.PrecedencePredicate reduced = Sharpen.Collections.Min(precedencePredicates
);
operands.AddItem(reduced);
}
opnds = Sharpen.Collections.ToArray(operands, new SemanticContext[operands.Count]
);
}
public override bool Equals(object obj)
{
if (this == obj)
{
return true;
}
if (!(obj is SemanticContext.AND))
{
return false;
}
SemanticContext.AND other = (SemanticContext.AND)obj;
return Arrays.Equals(this.opnds, other.opnds);
}
public override int GetHashCode()
{
return Arrays.HashCode(opnds);
}
public override bool Eval<_T0>(Recognizer<_T0> parser, RuleContext outerContext)
{
foreach (SemanticContext opnd in opnds)
{
if (!opnd.Eval(parser, outerContext))
{
return false;
}
}
return true;
}
public override string ToString()
{
return Utils.Join(opnds, "&&");
}
}
public class OR : SemanticContext
{
[NotNull]
public readonly SemanticContext[] opnds;
public OR(SemanticContext a, SemanticContext b)
{
ICollection<SemanticContext> operands = new HashSet<SemanticContext>();
if (a is SemanticContext.OR)
{
Sharpen.Collections.AddAll(operands, Arrays.AsList(((SemanticContext.OR)a).opnds)
);
}
else
{
operands.AddItem(a);
}
if (b is SemanticContext.OR)
{
Sharpen.Collections.AddAll(operands, Arrays.AsList(((SemanticContext.OR)b).opnds)
);
}
else
{
operands.AddItem(b);
}
IList<SemanticContext.PrecedencePredicate> precedencePredicates = FilterPrecedencePredicates
(operands);
if (!precedencePredicates.IsEmpty())
{
// interested in the transition with the highest precedence
SemanticContext.PrecedencePredicate reduced = Sharpen.Collections.Max(precedencePredicates
);
operands.AddItem(reduced);
}
this.opnds = Sharpen.Collections.ToArray(operands, new SemanticContext[operands.Count
]);
}
public override bool Equals(object obj)
{
if (this == obj)
{
return true;
}
if (!(obj is SemanticContext.OR))
{
return false;
}
SemanticContext.OR other = (SemanticContext.OR)obj;
return Arrays.Equals(this.opnds, other.opnds);
}
public override int GetHashCode()
{
return Arrays.HashCode(opnds) + 1;
}
// differ from AND slightly
public override bool Eval<_T0>(Recognizer<_T0> parser, RuleContext outerContext)
{
foreach (SemanticContext opnd in opnds)
{
if (opnd.Eval(parser, outerContext))
{
return true;
}
}
return false;
}
public override string ToString()
{
return Utils.Join(opnds, "||");
}
}
public static SemanticContext And(SemanticContext a, SemanticContext b)
{
if (a == null || a == None)
{
return b;
}
if (b == null || b == None)
{
return a;
}
SemanticContext.AND result = new SemanticContext.AND(a, b);
if (result.opnds.Length == 1)
{
return result.opnds[0];
}
return result;
}
/// <seealso cref="ParserATNSimulator.GetPredsForAmbigAlts(System.Collections.BitArray, ATNConfigSet, int)
/// ">ParserATNSimulator.GetPredsForAmbigAlts(System.Collections.BitArray, ATNConfigSet, int)
/// </seealso>
public static SemanticContext Or(SemanticContext a, SemanticContext b)
{
if (a == null)
{
return b;
}
if (b == null)
{
return a;
}
if (a == None || b == None)
{
return None;
}
SemanticContext.OR result = new SemanticContext.OR(a, b);
if (result.opnds.Length == 1)
{
return result.opnds[0];
}
return result;
}
private static IList<SemanticContext.PrecedencePredicate> FilterPrecedencePredicates
<_T0>(ICollection<_T0> collection) where _T0:SemanticContext
{
List<SemanticContext.PrecedencePredicate> result = null;
for (IEnumerator<SemanticContext> iterator = collection.GetEnumerator(); iterator
.HasNext(); )
{
SemanticContext context = iterator.Next();
if (context is SemanticContext.PrecedencePredicate)
{
if (result == null)
{
result = new List<SemanticContext.PrecedencePredicate>();
}
result.AddItem((SemanticContext.PrecedencePredicate)context);
iterator.Remove();
}
}
if (result == null)
{
return Sharpen.Collections.EmptyList();
}
return result;
}
}
}