package org.jactr.tools.analysis.production.endstates.impl;
/*
* default logging
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.antlr.runtime.tree.CommonTree;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.slot.IConditionalSlot;
import org.jactr.io.antlr3.builder.JACTRBuilder;
import org.jactr.io.antlr3.misc.ASTSupport;
import org.jactr.tools.analysis.production.endstates.BufferEndState;
import org.jactr.tools.analysis.production.endstates.BufferEndStates;
public class BufferStateUtilities
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(BufferStateUtilities.class);
/**
* {@value #YES} means that given the values and the conditions the slots
* have, they COULD be equivalent (but still might not be)<br>
* {@value #NO} means that given the values and the conditions, the two slots
* can never be equivalent <br>
* {@value #AMBIGUOUS} means that the given values and conditions are not
* sufficient to make any judgement.<br>
*
* @author harrison
*/
static public enum Consistent {
YES, NO, AMBIGUOUS
};
/**
* this will search through all the conditions and queries looking for more
* information about variableName. When it finds another slot that matches to
* that variable name, all other non-variable conditions for that slot are
* saved and remapped to the provided slotName. ex: <br>
* <code>
* (p
* =goal>
* isa fact
* - arg1 Z
* arg1 =value
*
* ==>
* +retrieval>
* isa other-fact
* argA =value
* )
* </code>
* <br>
* We know that other-fact.argA cannot be null OR Z.<br>
* Ideally this method should be recursively because some mean modeler might
* use a whole slew of variable indirections within a single production.. but
* that will be for version 2.
*
* @param slotName
* @param variableName
* @param endStates
* @return
*/
static public Collection<CommonTree> expandVariable(String slotName,
String variableName, BufferEndStates endStates)
{
Collection<CommonTree> rtn = new ArrayList<CommonTree>();
Set<String> slotNamesToExpand = new TreeSet<String>();
for (CommonTree condition : endStates.getMapOfTrees(
JACTRBuilder.MATCH_CONDITION).values())
{
slotNamesToExpand.clear();
Map<Integer, Collection<CommonTree>> allSlots = getSlots(condition);
/*
* zip through the variables to see if anyone references the equality of
* the provided variable name..
*/
if (allSlots.containsKey(JACTRBuilder.VARIABLE))
for (CommonTree slot : allSlots.get(JACTRBuilder.VARIABLE))
if (conditionIs(slot, IConditionalSlot.EQUALS)
&& variableName.equalsIgnoreCase(getContent(slot)))
slotNamesToExpand.add(ASTSupport.getName(slot).toLowerCase());
/*
* now we have all the names of the slots that reference variableName
* within this condition. We need to go through once more to grab all the
* actual references to this slot (other than the variables)
*/
for (CommonTree slot : getNonVariables(allSlots))
{
String name = ASTSupport.getName(slot);
if (slotNamesToExpand.contains(name.toLowerCase()))
rtn.add(BufferEndState.getSupport().createSlot(slotName,
(CommonTree)slot.getChild(1), (CommonTree)slot.getChild(2)));
}
}
/*
* sometimes we cant resolve much of anything, but we do know that
* the the slot name is not going to be null/nil...
*/
if(rtn.size()==0)
{
rtn.add(BufferEndState.getSupport().createSlot(slotName,
IConditionalSlot.NOT_EQUALS, BufferEndState.NULL));
rtn.add(BufferEndState.getSupport().createSlot(slotName,
IConditionalSlot.NOT_EQUALS, BufferEndState.NIL));
}
return rtn;
}
/**
* return a map of collections of slot ASTs contained by the condition or
* action. the map is keyed on the type of content in the slot, typically
* {@link JACTRBuilder#IDENTIFIER}, {@link JACTRBuilder#VARIABLE}, or
* {@link JACTRBuilder#NUMBER}
*
* @param conditionOrAction
* @return
*/
static public Map<Integer, Collection<CommonTree>> getSlots(
CommonTree conditionOrAction)
{
Map<Integer, Collection<CommonTree>> rtn = new TreeMap<Integer, Collection<CommonTree>>();
for (CommonTree slot : ASTSupport.getTrees(conditionOrAction,
JACTRBuilder.SLOT))
{
// slot(name condition content)
int contentType = slot.getChild(2).getType();
Collection<CommonTree> slots = rtn.get(contentType);
if (slots == null)
{
slots = new ArrayList<CommonTree>();
rtn.put(contentType, slots);
}
slots.add(slot);
}
return rtn;
}
/**
* return all slots that arent variables
*
* @param mapOfSlots
* @return
*/
static public Collection<CommonTree> getNonVariables(
Map<Integer, Collection<CommonTree>> mapOfSlots)
{
ArrayList<CommonTree> rtn = new ArrayList<CommonTree>();
for (int type : new int[] { JACTRBuilder.IDENTIFIER, JACTRBuilder.NUMBER,
JACTRBuilder.STRING })
{
Collection<CommonTree> slots = mapOfSlots.get(type);
if (slots != null) rtn.addAll(slots);
}
return rtn;
}
/**
* return all slots that are equality conditions (aka assignments), even
* variables
*
* @param mapOfTrees
* @return
*/
static public Collection<CommonTree> getAssignments(
Map<Integer, Collection<CommonTree>> mapOfTrees)
{
ArrayList<CommonTree> rtn = new ArrayList<CommonTree>();
for (Collection<CommonTree> slots : mapOfTrees.values())
for (CommonTree slot : slots)
if (conditionIs(slot, IConditionalSlot.EQUALS)) rtn.add(slot);
return rtn;
}
static public boolean contentIsType(CommonTree slot, int type)
{
return slot.getChild(2).getType() == type;
}
static public String getContent(CommonTree slot)
{
return slot.getChild(2).getText();
}
/**
* uses {@link IConditionalSlot} condition constants, not {@link JACTRBuilder}
*
* @param slot
* @param condition
* @return
*/
static public boolean conditionIs(CommonTree slot, int condition)
{
int cond = slot.getChild(1).getType();
if (cond == JACTRBuilder.EQUALS && condition == IConditionalSlot.EQUALS)
return true;
if (cond == JACTRBuilder.NOT && condition == IConditionalSlot.NOT_EQUALS)
return true;
if (cond == JACTRBuilder.GT && condition == IConditionalSlot.GREATER_THAN)
return true;
if (cond == JACTRBuilder.GTE
&& condition == IConditionalSlot.GREATER_THAN_EQUALS) return true;
if (cond == JACTRBuilder.LT && condition == IConditionalSlot.LESS_THAN)
return true;
if (cond == JACTRBuilder.LTE
&& condition == IConditionalSlot.LESS_THAN_EQUALS) return true;
return false;
}
/**
* compare two slots to see if they are applicable, this is just a name check
*
* @param endStateSlot
* @param conditionalSlot
* @return
*/
static public boolean slotIsApplicable(CommonTree endStateSlot,
CommonTree conditionalSlot)
{
return conditionalSlot.getChild(0).getText().equalsIgnoreCase(
endStateSlot.getChild(0).getText());
}
/**
* return true if the endstate slot is consistent with the conditional slot.
* this will check the conditions on both the slots and compare their values
* accordingly. The values should NEVER be variables in either slot.
* similarly, before calling this,
* {@link #slotIsApplicable(CommonTree, CommonTree)} should have returned
* true.<br>
* <br>
* Currently this will return ambiguous if either slot condition is anything
* but equals or not
*
* @param endStateSlot
* @param conditionalSlot
* @throws IllegalStateException
* if either is a variable or the condition type is not recognized
* @return {@link Consistent}
*/
static public Consistent isConsistentWith(CommonTree endStateSlot,
CommonTree conditionalSlot)
{
int endCondition = endStateSlot.getChild(1).getType();
int queryCondition = conditionalSlot.getChild(1).getType();
if (endStateSlot.getChild(2).getType() == JACTRBuilder.VARIABLE
|| conditionalSlot.getChild(2).getType() == JACTRBuilder.VARIABLE)
throw new IllegalStateException(
"neither conditional nor end state slots may be variables");
String endContent = endStateSlot.getChild(2).getText();
String queryContent = conditionalSlot.getChild(2).getText();
if (endCondition == JACTRBuilder.EQUALS)
{
// both equal
if (queryCondition == endCondition)
if (endContent.equalsIgnoreCase(queryContent))
return Consistent.YES;
else
return Consistent.NO;
if (queryCondition == JACTRBuilder.NOT)
if (endContent.equalsIgnoreCase(queryContent))
// a=1 a!=1
return Consistent.NO;
else
// a=1 a!=2
return Consistent.YES;
return Consistent.AMBIGUOUS;
}
else if (endCondition == JACTRBuilder.NOT)
{
// a!=2 a!=3
if (queryCondition == endCondition) return Consistent.YES;
if (queryCondition == JACTRBuilder.EQUALS)
if (endContent.equalsIgnoreCase(queryContent))
// a!=2 a=2
return Consistent.NO;
else
// a!=2 a=4
return Consistent.YES;
return Consistent.AMBIGUOUS;
}
else
return Consistent.AMBIGUOUS;
}
}