// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.prelude.semantics.rule;
import java.util.Iterator;
import java.util.List;
import com.yahoo.prelude.semantics.engine.Choicepoint;
import com.yahoo.prelude.semantics.engine.FlattenedItem;
import com.yahoo.prelude.semantics.engine.RuleEvaluation;
/**
* A condition which greedily matches anything, represented as "..."
*
* @author Jon S Bratseth
*/
public class EllipsisCondition extends Condition {
/** Whether this ellipsis is actually referable (enclosed in []) or not */
private boolean referable;
/** Creates a referable ellipsis condition with no label */
public EllipsisCondition() {
this(true);
}
/** Creates an ellipsis condition with no label */
public EllipsisCondition(boolean referable) {
this(null,referable);
}
/** Creates an ellipsis condition */
public EllipsisCondition(String label,boolean referable) {
super(label);
this.referable=referable;
if (referable)
setContextName("...");
}
public EllipsisCondition(String label,String context) {
super(label,context);
}
public boolean doesMatch(RuleEvaluation e) {
// We use a choice point to remember which untried alternatives are not tried (if any)
// We never need to backtrack to this choice - backtracking is done by the parent
// if this choice gives a global invalid state
Choicepoint choicepoint=e.getChoicepoint(this,false);
if (choicepoint==null) { // First try
choicepoint=e.getChoicepoint(this,true);
}
else {
if (!choicepoint.isOpen()) return false;
}
// Match all the rest of the items the first time, then all except the last item and so on
int numberOfTermsToMatch=e.itemCount() - e.currentPosition() - choicepoint.tryCount();
if (numberOfTermsToMatch<0) {
choicepoint.close();
return false;
}
choicepoint.addTry();
String matchedTerms=matchTerms(numberOfTermsToMatch,e);
e.setValue(matchedTerms);
return true;
}
private String matchTerms(int numberOfTerms,RuleEvaluation e) {
StringBuilder b=new StringBuilder();
for (int i=0; i items) {
StringBuilder buffer=new StringBuilder();
for (Iterator i=items.iterator(); i.hasNext(); ) {
buffer.append(i.next().toString());
if (i.hasNext())
buffer.append(" ");
}
return buffer.toString();
}
/** Returns whether this ellipsis condition can be referred from a production */
public boolean isReferable() {
return referable || super.isReferable();
}
/** Sets whether this ellipsis condition can be referred from a production or not */
public void setReferable(boolean referable) {
this.referable=referable;
if (referable && getContextName()==null)
setContextName("...");
if (!referable && "...".equals(getContextName()))
setContextName(null);
}
protected boolean hasOpenChoicepoint(RuleEvaluation e) {
Choicepoint choicepoint=e.getChoicepoint(this,false);
if (choicepoint==null) return false; // Not tried yet
if (!choicepoint.isOpen()) return false;
return true;
}
protected boolean isDefaultContextName() {
return (getContextName()==null || getContextName().equals("..."));
}
protected String toInnerString() {
if (referable)
return "[...]";
else
return "...";
}
}