protected virtual GrammarAST TranslateLeftFactoredElement(GrammarAST element, string factoredRule, bool variant, DecisionFactorMode mode, bool includeFactoredElement)
{
if (mode == DecisionFactorMode.PARTIAL_UNFACTORED && includeFactoredElement)
{
throw new ArgumentException("Cannot include the factored element in unfactored alternatives.");
}
if (mode == DecisionFactorMode.COMBINED_FACTOR)
{
throw new InvalidOperationException("Cannot return a combined answer.");
}
Debug.Assert(!mode.IncludeFactoredAlts() || !mode.IncludeUnfactoredAlts());
switch (element.Type)
{
case ANTLRParser.ASSIGN:
case ANTLRParser.PLUS_ASSIGN:
{
/* label=a
*
* ==>
*
* factoredElement label=a_factored
*/
GrammarAST translatedChildElement = TranslateLeftFactoredElement((GrammarAST)element.GetChild(1), factoredRule, variant, mode, includeFactoredElement);
if (translatedChildElement == null)
{
return null;
}
RuleAST ruleAST = (RuleAST)element.GetAncestor(ANTLRParser.RULE);
#if false
LOGGER.log(Level.WARNING, "Could not left factor ''{0}'' out of decision in rule ''{1}'': labeled rule references are not yet supported.",
new object[] { factoredRule, ruleAST.GetChild(0).Text });
#endif
return null;
//if (!translatedChildElement.IsNil)
//{
// GrammarAST root = (GrammarAST)adaptor.Nil();
// object factoredElement = translatedChildElement;
// if (outerRule)
// {
// adaptor.AddChild(root, factoredElement);
// }
// string action = string.Format("_localctx.{0} = (ContextType)_localctx.getParent().getChild(_localctx.getParent().getChildCount() - 1);", element.GetChild(0).Text);
// adaptor.AddChild(root, new ActionAST(adaptor.CreateToken(ANTLRParser.ACTION, action)));
// return root;
//}
//else
//{
// GrammarAST root = (GrammarAST)adaptor.Nil();
// object factoredElement = adaptor.DeleteChild(translatedChildElement, 0);
// if (outerRule)
// {
// adaptor.AddChild(root, factoredElement);
// }
// adaptor.AddChild(root, element);
// adaptor.ReplaceChildren(element, 1, 1, translatedChildElement);
// return root;
//}
}
case ANTLRParser.RULE_REF:
{
if (factoredRule.Equals(element.Token.Text))
{
if (!mode.IncludeFactoredAlts())
{
return null;
}
if (includeFactoredElement)
{
// this element is already left factored
return element;
}
GrammarAST root1 = (GrammarAST)adaptor.Nil();
root1.AddChild((ITree)adaptor.Create(TokenConstants.Epsilon, "EPSILON"));
root1.DeleteChild(0);
return root1;
}
Rule targetRule;
if (!_rules.TryGetValue(element.Token.Text, out targetRule))
{
return null;
}
RuleVariants ruleVariants = CreateLeftFactoredRuleVariant(targetRule, factoredRule);
switch (ruleVariants)
{
case RuleVariants.NONE:
if (!mode.IncludeUnfactoredAlts())
{
return null;
}
// just call the original rule (leave the element unchanged)
return element;
case RuleVariants.FULLY_FACTORED:
if (!mode.IncludeFactoredAlts())
{
return null;
}
break;
case RuleVariants.PARTIALLY_FACTORED:
break;
default:
throw new InvalidOperationException();
}
string marker = mode.IncludeFactoredAlts() ? ATNSimulator.RuleLfVariantMarker : ATNSimulator.RuleNolfVariantMarker;
element.SetText(element.Text + marker + factoredRule);
GrammarAST root = (GrammarAST)adaptor.Nil();
if (includeFactoredElement)
{
Debug.Assert(mode.IncludeFactoredAlts());
RuleRefAST factoredRuleRef = new RuleRefAST(adaptor.CreateToken(ANTLRParser.RULE_REF, factoredRule));
factoredRuleRef.SetOption(SUPPRESS_ACCESSOR, (GrammarAST)adaptor.Create(ANTLRParser.ID, "true"));
Rule factoredRuleDef = _rules[factoredRule];
if (factoredRuleDef is LeftRecursiveRule)
{
factoredRuleRef.SetOption(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME, (GrammarAST)adaptor.Create(ANTLRParser.INT, "0"));
}
if (factoredRuleDef.args != null && factoredRuleDef.args.Size() > 0)
{
throw new NotImplementedException("Cannot left-factor rules with arguments yet.");
}
adaptor.AddChild(root, factoredRuleRef);
}
adaptor.AddChild(root, element);
return root;
}
case ANTLRParser.BLOCK:
{
GrammarAST cloned = element.DupTree();
if (!TranslateLeftFactoredDecision(cloned, factoredRule, variant, mode, includeFactoredElement))
{
return null;
}
if (cloned.ChildCount != 1)
{
return null;
}
GrammarAST root = (GrammarAST)adaptor.Nil();
for (int i = 0; i < cloned.GetChild(0).ChildCount; i++)
{
adaptor.AddChild(root, cloned.GetChild(0).GetChild(i));
}
return root;
}
case ANTLRParser.POSITIVE_CLOSURE:
{
/* a+
*
* =>
*
* factoredElement a_factored a*
*/
GrammarAST originalChildElement = (GrammarAST)element.GetChild(0);
GrammarAST translatedElement = TranslateLeftFactoredElement(originalChildElement.DupTree(), factoredRule, variant, mode, includeFactoredElement);
if (translatedElement == null)
{
return null;
}
GrammarAST closure = new StarBlockAST(ANTLRParser.CLOSURE, adaptor.CreateToken(ANTLRParser.CLOSURE, "CLOSURE"), null);
adaptor.AddChild(closure, originalChildElement);
GrammarAST root = (GrammarAST)adaptor.Nil();
if (mode.IncludeFactoredAlts())
{
if (includeFactoredElement)
{
object factoredElement = adaptor.DeleteChild(translatedElement, 0);
adaptor.AddChild(root, factoredElement);
}
}
adaptor.AddChild(root, translatedElement);
adaptor.AddChild(root, closure);
return root;
}
case ANTLRParser.CLOSURE:
case ANTLRParser.OPTIONAL:
// not yet supported
if (mode.IncludeUnfactoredAlts())
{
return element;
}
return null;
case ANTLRParser.DOT:
// ref to imported grammar, not yet supported
if (mode.IncludeUnfactoredAlts())
{
return element;
}
return null;
case ANTLRParser.ACTION:
case ANTLRParser.SEMPRED:
if (mode.IncludeUnfactoredAlts())
{
return element;
}
return null;
case ANTLRParser.WILDCARD:
case ANTLRParser.STRING_LITERAL:
case ANTLRParser.TOKEN_REF:
case ANTLRParser.NOT:
// terminals
if (mode.IncludeUnfactoredAlts())
{
return element;
}
return null;
case ANTLRParser.EPSILON:
// empty tree
if (mode.IncludeUnfactoredAlts())
{
return element;
}
return null;
default:
// unknown
return null;
}
}