in jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/LPInterpreter.java [243:636]
protected StateFlag run() {
int pc = 0; // Program code counter
int ac = 0; // Program arg code counter
RuleClauseCode clause = null; // The clause being executed
ChoicePointFrame choice = null;
byte[] code;
Object[] args;
boolean traceOn = engine.isTraceOn();
boolean recordDerivations = engine.getDerivationLogging();
main: while (cpFrame != null) {
// restore choice point
if (cpFrame instanceof ChoicePointFrame) {
choice = (ChoicePointFrame)cpFrame;
if (!choice.hasNext()) {
// No more choices left in this choice point
cpFrame = choice.getLink();
if (traceOn) logger.info("FAIL in clause " + choice.envFrame.clause + " choices exhausted");
continue main;
}
clause = choice.nextClause();
// Create an execution environment for the new choice of clause
if (recordDerivations) {
envFrame = new EnvironmentFrameWithDerivation(clause);
} else {
envFrame = new EnvironmentFrame(clause);
}
envFrame.linkTo(choice.envFrame);
envFrame.cpc = choice.cpc;
envFrame.cac = choice.cac;
// Restore the choice point state
System.arraycopy(choice.argVars, 0, argVars, 0, RuleClauseCode.MAX_ARGUMENT_VARS);
int trailMark = choice.trailIndex;
if (trailMark < trail.size()) {
unwindTrail(trailMark);
}
pc = ac = 0;
if (recordDerivations) {
((EnvironmentFrameWithDerivation)envFrame).initDerivationRecord(argVars);
}
if (traceOn) logger.info("ENTER " + clause + " : " + getArgTrace());
// then fall through into the recreated execution context for the new call
} else if (cpFrame instanceof TripleMatchFrame) {
TripleMatchFrame tmFrame = (TripleMatchFrame)cpFrame;
// Restore the calling context
envFrame = tmFrame.envFrame;
clause = envFrame.clause;
int trailMark = tmFrame.trailIndex;
if (trailMark < trail.size()) {
unwindTrail(trailMark);
}
// Find the next choice result directly
if (!tmFrame.nextMatch(this)) {
// No more matches
cpFrame = cpFrame.getLink();
if (traceOn) logger.info("TRIPLE match (" + tmFrame.goal +") -> FAIL");
continue main;
}
if (traceOn) {
logger.info("TRIPLE match (" + tmFrame.goal +") -> " + getArgTrace());
logger.info("RENTER " + clause);
}
pc = tmFrame.cpc;
ac = tmFrame.cac;
if (recordDerivations) {
if (envFrame instanceof EnvironmentFrameWithDerivation) {
((EnvironmentFrameWithDerivation)envFrame).noteMatch(tmFrame.goal, pc);
}
}
// then fall through to the execution context in which the the match was called
} else if (cpFrame instanceof TopLevelTripleMatchFrame) {
TopLevelTripleMatchFrame tmFrame = (TopLevelTripleMatchFrame)cpFrame;
// Find the next choice result directly
if (!tmFrame.nextMatch(this)) {
// No more matches
cpFrame = cpFrame.getLink();
if (traceOn) logger.info("TRIPLE match (" + tmFrame.goal +") -> FAIL");
continue main;
} else {
// Match but this is the top level so return the triple directly
if (traceOn) logger.info("TRIPLE match (" + tmFrame.goal +") ->");
return StateFlag.SATISFIED;
}
} else if (cpFrame instanceof ConsumerChoicePointFrame) {
ConsumerChoicePointFrame ccp = (ConsumerChoicePointFrame)cpFrame;
// Restore the calling context
envFrame = ccp.envFrame;
clause = envFrame.clause;
if (traceOn) logger.info("RESTORE " + clause + ", due to tabled goal " + ccp.generator.goal);
int trailMark = ccp.trailIndex;
if (trailMark < trail.size()) {
unwindTrail(trailMark);
}
// Find the next choice result directly
StateFlag state = ccp.nextMatch(this);
if (state == StateFlag.FAIL) {
// No more matches
cpFrame = cpFrame.getLink();
if (traceOn) logger.info("FAIL " + clause);
continue main;
} else if (state == StateFlag.SUSPEND) {
// Require other generators to cycle before resuming this one
preserveState(ccp);
iContext.notifyBlockedOn(ccp);
cpFrame = cpFrame.getLink();
if (traceOn)logger.info("SUSPEND " + clause);
continue main;
}
pc = ccp.cpc;
ac = ccp.cac;
if (recordDerivations) {
if (envFrame instanceof EnvironmentFrameWithDerivation) {
((EnvironmentFrameWithDerivation)envFrame).noteMatch(ccp.goal, pc);
}
}
// then fall through to the execution context in which the the match was called
} else {
throw new ReasonerException("Internal error in backward rule system, unrecognized choice point");
}
engine.incrementProfile(clause);
interpreter: while (envFrame != null) {
// Start of bytecode intepreter loop
// Init the state variables
pVars = envFrame.pVars;
int yi, ai, ti;
Node arg, constant;
code = clause.getCode();
args = clause.getArgs();
while (true) {
switch (code[pc++]) {
case RuleClauseCode.TEST_BOUND:
ai = code[pc++];
if (deref(argVars[ai]).isVariable()) {
if (traceOn) logger.info("FAIL " + clause);
continue main;
}
break;
case RuleClauseCode.TEST_UNBOUND:
ai = code[pc++];
if (! deref(argVars[ai]).isVariable()) {
if (traceOn) logger.info("FAIL " + clause);
continue main;
}
break;
case RuleClauseCode.ALLOCATE:
int envSize = code[pc++];
envFrame.allocate(envSize);
pVars = envFrame.pVars;
break;
case RuleClauseCode.GET_VARIABLE :
yi = code[pc++];
ai = code[pc++];
pVars[yi] = argVars[ai];
break;
case RuleClauseCode.GET_TEMP :
ti = code[pc++];
ai = code[pc++];
tVars[ti] = argVars[ai];
break;
case RuleClauseCode.GET_CONSTANT :
ai = code[pc++];
arg = argVars[ai];
if (arg instanceof Node_RuleVariable) arg = ((Node_RuleVariable)arg).deref();
constant = (Node) args[ac++];
if (arg instanceof Node_RuleVariable) {
bind(arg, constant);
} else {
if (!arg.sameValueAs(constant)) {
if (traceOn) logger.info("FAIL " + clause);
continue main;
}
}
break;
case RuleClauseCode.GET_FUNCTOR:
Functor func = (Functor)args[ac++];
boolean match = false;
Node o = argVars[2];
if (o instanceof Node_RuleVariable) o = ((Node_RuleVariable)o).deref();
if (Functor.isFunctor(o)) {
Functor funcArg = (Functor)o.getLiteralValue();
if (funcArg.getName().equals(func.getName())) {
if (funcArg.getArgLength() == func.getArgLength()) {
Node[] fargs = funcArg.getArgs();
for (int i = 0; i < fargs.length; i++) {
argVars[i+3] = fargs[i];
}
match = true;
}
}
} else if (o.isVariable()) {
// Construct a new functor in place
Node[] fargs = new Node[func.getArgLength()];
Node[] templateArgs = func.getArgs();
for (int i = 0; i < fargs.length; i++) {
Node template = templateArgs[i];
if (template.isVariable()) template = new Node_RuleVariable(null, i+3);
fargs[i] = template;
argVars[i+3] = template;
}
Node newFunc = Functor.makeFunctorNode(func.getName(), fargs);
bind(((Node_RuleVariable)o).deref(), newFunc);
match = true;
}
if (!match) {
if (traceOn) logger.info("FAIL " + clause);
continue main; // fail to unify functor shape
}
break;
case RuleClauseCode.UNIFY_VARIABLE :
yi = code[pc++];
ai = code[pc++];
if (!unify(argVars[ai], pVars[yi])) {
if (traceOn) logger.info("FAIL " + clause);
continue main;
}
break;
case RuleClauseCode.UNIFY_TEMP :
ti = code[pc++];
ai = code[pc++];
if (!unify(argVars[ai], tVars[ti])) {
if (traceOn) logger.info("FAIL " + clause);
continue main;
}
break;
case RuleClauseCode.PUT_NEW_VARIABLE:
yi = code[pc++];
ai = code[pc++];
argVars[ai] = pVars[yi] = new Node_RuleVariable(null, yi);
break;
case RuleClauseCode.PUT_VARIABLE:
yi = code[pc++];
ai = code[pc++];
argVars[ai] = pVars[yi];
break;
case RuleClauseCode.PUT_DEREF_VARIABLE:
yi = code[pc++];
ai = code[pc++];
argVars[ai] = deref(pVars[yi]);
break;
case RuleClauseCode.PUT_TEMP:
ti = code[pc++];
ai = code[pc++];
argVars[ai] = tVars[ti];
break;
case RuleClauseCode.PUT_CONSTANT:
ai = code[pc++];
argVars[ai] = (Node)args[ac++];
break;
case RuleClauseCode.CLEAR_ARG:
ai = code[pc++];
argVars[ai] = new Node_RuleVariable(null, ai);
break;
case RuleClauseCode.MAKE_FUNCTOR:
Functor f = (Functor)args[ac++];
Node[] fargs = new Node[f.getArgLength()];
System.arraycopy(argVars, 3, fargs, 0, fargs.length);
argVars[2] = Functor.makeFunctorNode(f.getName(), fargs);
break;
case RuleClauseCode.LAST_CALL_PREDICATE:
// TODO: improved implementation of last call case
case RuleClauseCode.CALL_PREDICATE:
List<RuleClauseCode> clauses = ((RuleClauseCodeList) args[ac++]).getList();
// Check if this call is now grounded
boolean groundCall = isGrounded(argVars[0]) && isGrounded(argVars[1]) && isGrounded(argVars[2]);
setupClauseCall(pc, ac, clauses, groundCall);
setupTripleMatchCall(pc, ac);
continue main;
case RuleClauseCode.CALL_PREDICATE_INDEX:
// This code path is experimental, don't yet know if it has enough
// performance benefit to justify the cost of maintaining it.
clauses = ((RuleClauseCodeList) args[ac++]).getList();
// Check if we can futher index the clauses
if (!argVars[2].isVariable()) {
clauses = engine.getRuleStore().codeFor(
new TriplePattern(argVars[0], argVars[1], argVars[2]));
}
setupClauseCall(pc, ac, clauses, false);
setupTripleMatchCall(pc, ac);
continue main;
case RuleClauseCode.CALL_TRIPLE_MATCH:
setupTripleMatchCall(pc, ac);
continue main;
case RuleClauseCode.CALL_TABLED:
setupTabledCall(pc, ac);
continue main;
case RuleClauseCode.CALL_WILD_TABLED:
Node predicate = deref(argVars[1]);
if (engine.getRuleStore().isTabled(predicate)) {
setupTabledCall(pc, ac);
} else {
// normal call set up
clauses = engine.getRuleStore().codeFor(
new TriplePattern(argVars[0], predicate, argVars[2]));
if (clauses != null) setupClauseCall(pc, ac, clauses, false);
setupTripleMatchCall(pc, ac);
}
continue main;
case RuleClauseCode.PROCEED:
pc = envFrame.cpc;
ac = envFrame.cac;
if (traceOn) logger.info("EXIT " + clause);
if (choice != null) choice.noteSuccess();
if (recordDerivations && envFrame.getRule() != null) {
if (envFrame instanceof EnvironmentFrameWithDerivation) {
EnvironmentFrameWithDerivation efd = (EnvironmentFrameWithDerivation) envFrame;
Triple result = efd.getResult();
List<Triple> matches = efd.getMatchList();
BackwardRuleInfGraphI infGraph = engine.getInfGraph();
RuleDerivation d = new RuleDerivation(envFrame.getRule(), result, matches, infGraph);
infGraph.logDerivation(result, d);
// Also want to record this result in the calling frame
if (envFrame.link instanceof EnvironmentFrameWithDerivation) {
EnvironmentFrameWithDerivation pefd = (EnvironmentFrameWithDerivation)envFrame.link;
pefd.noteMatch(new TriplePattern(result), pc);
}
}
}
envFrame = (EnvironmentFrame) envFrame.link;
if (envFrame != null) {
clause = envFrame.clause;
}
continue interpreter;
case RuleClauseCode.CALL_BUILTIN:
Builtin builtin = (Builtin)args[ac++];
if (context == null) {
BBRuleContext bbcontext = new BBRuleContext(engine.getInfGraph());
bbcontext.setEnv(new LPBindingEnvironment(this));
context = bbcontext;
}
context.setRule(clause.getRule());
if (!builtin.bodyCall(argVars, code[pc++], context)) {
if (traceOn) logger.info("FAIL " + clause + ", due to " + builtin.getName());
continue main;
}
break;
default :
throw new ReasonerException("Internal error in backward rule system\nIllegal op code");
}
}
// End of innter code loop
}
// End of bytecode interpreter loop, gets to here if we complete an AND chain
return StateFlag.ACTIVE;
}
// Gets to here if we have run out of choice point frames
return StateFlag.FAIL;
}