blob: 6e93d41bad017b43f6d9f1c1633bfa4c88f67d95 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Hisashi MIYASHITA - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.ai.xmlstore.nvdl.fm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLAction;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLActionManager;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLAttributeSection;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLElement;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLMode;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLNoResultAction;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLResultAction;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLRule;
import org.eclipse.actf.ai.xmlstore.nvdl.model.NVDLRules;
/*
Moore PDA
*/
public class PDA {
// Internal state -----------------------------------------------------------------
private ArrayList<StackElement> currentContext = new ArrayList<StackElement>();
private ArrayList<StackElement> nextContext = new ArrayList<StackElement>();
private boolean isAttributeAttached;
// --------------------------------------------------------------------------------
// Compiled Result -----------------------------------------------------------------
private final State initialState;
// --------------------------------------------------------------------------------
private static class StackElement extends Interpretation {
public final State state;
public final StackElement parent;
// To avoid duplicatedly merging branches.
public final boolean firstBranch;
public Interpretation getParent() {
return parent;
}
private StackElement(NVDLMode mode, NVDLAction action,
NVDLElement e, StackElement parent, State state,
boolean firstBranch) {
super(mode, action, e);
this.parent = parent;
this.state = state;
this.firstBranch = firstBranch;
}
static StackElement newEffectiveStackElement(StackElement parent,
State state, NVDLElement element,
boolean firstBranch) {
return new StackElement(state.mode, state.action, element, parent, state,
firstBranch);
}
static StackElement newNoneffectiveStackElement(StackElement parent,
NVDLElement element) {
return new StackElement(null, null, element, parent, parent.state, true);
}
}
private static class AttrInterpretation extends Interpretation {
public final StackElement parent;
public Interpretation getParent() {
return parent;
}
private AttrInterpretation(NVDLMode mode, NVDLAction action,
StackElement parent) {
super(mode, action, null);
this.parent = parent;
}
static AttrInterpretation newAttrInterpretation(StackElement parent,
State state) {
return new AttrInterpretation(state.mode, state.action, parent);
}
}
// E ~= {Q' -> 2^Q'}, e \in E = rule(q')
private static class Edge {
final NVDLAction.Context allowableContext;
final Mode nextMode;
static class Mode {
static class Dest {
final NVDLRule rule;
final State[] nextStates;
Dest(NVDLRule rule, State[] nextStates) {
this.rule = rule;
this.nextStates = nextStates;
}
public String toString() {
return "Dest:" + rule.toString();
}
}
private Dest[] dests;
public State[] nextStates(String ns, boolean isElement) {
for (int i = 0; i < dests.length; i++) {
if (dests[i].rule.match(ns, isElement)) return dests[i].nextStates;
}
// notreachable
return null;
}
}
boolean match(NVDLElement e) {
return allowableContext.match(e);
}
Edge(NVDLAction.Context allowableContext, Mode nextMode) {
this.allowableContext = allowableContext;
this.nextMode = nextMode;
}
public String toString() {
String ret = "Edge:";
if (allowableContext != null)
return ret + allowableContext.toString();
else
return ret;
}
}
// Q' ~= Mode X Action
private static class State {
String id;
Edge defaultEdge;
Edge[] contextEdges;
private Edge.Mode nextMode(NVDLElement e) {
assert (e != null) || (contextEdges == null);
if (contextEdges != null) {
for (int i = 0; i < contextEdges.length; i++) {
if (contextEdges[i].match(e)) return contextEdges[i].nextMode;
}
}
return defaultEdge.nextMode;
}
State[] next(NVDLElement e, String ns, boolean isElement) {
Edge.Mode nextMode = nextMode(e);
return nextMode.nextStates(ns, isElement);
}
final NVDLMode mode;
final NVDLAction action;
State(NVDLMode mode, NVDLAction action) {
this.mode = mode;
this.action = action;
}
String getID() {
return id;
}
public String toString() {
return ("PDA State-ID:" + id
+ " Mode:" + mode
+ " Action:" + action);
}
}
private void finishTransition() {
// ArrayList<StackElement> tmp = currentContext;
currentContext = nextContext;
nextContext = new ArrayList<StackElement>(currentContext.size());
// nextContext.clear();
}
private boolean nextStateTransition(StackElement stack, NVDLElement e) {
boolean firstBranch = true;
State[] nextStates = stack.state.next(e.parent, e.ns, true);
for (int i = 0; i < nextStates.length; i++) {
StackElement newStack = StackElement.newEffectiveStackElement(stack, nextStates[i],
e, firstBranch);
nextContext.add(newStack);
firstBranch = false;
}
return (nextStates.length > 0);
}
// --------------------------------------------------------------------------------
// APIs
// --------------------------------------------------------------------------------
public boolean startElement(NVDLElement e) {
boolean flag = false;
int size = currentContext.size();
for (int i = 0; i < size; i++) {
StackElement stack = currentContext.get(i);
if (!e.isSectionHead()) {
// push current state.
StackElement se = StackElement.newNoneffectiveStackElement(stack, e);
nextContext.add(se);
} else {
flag = nextStateTransition(stack, e);
}
}
finishTransition();
return flag;
}
public boolean endElement() {
boolean flag = false;
int size = currentContext.size();
for (int i = 0; i < size; i++) {
StackElement stack = currentContext.get(i);
if (!stack.firstBranch) continue;
StackElement parent = stack.parent;
assert(parent != null);
if (parent.state != stack.state) {
flag = true;
}
nextContext.add(parent);
}
finishTransition();
return flag;
}
public boolean isAttributeAttached() {
return isAttributeAttached;
}
public List<Interpretation> getAttributeInterpretation(Interpretation current,
NVDLAttributeSection as) {
StackElement stack = (StackElement) current;
isAttributeAttached = false;
List<Interpretation> result = new ArrayList<Interpretation>();
State[] nextStates = stack.state.next(as.getBaseElement(),
as.getNamespace(),
false);
for (int i = 0; i < nextStates.length; i++) {
AttrInterpretation ai = AttrInterpretation.newAttrInterpretation(stack, nextStates[i]);
if (ai.isDispatch()) {
result.add(ai);
}
if (ai.isAttach()) {
isAttributeAttached = true;
}
}
assert (isAttributeAttached || (result.size() > 0));
return result;
}
public List getCurrentInterpretations() {
return currentContext;
}
public enum MatchResult {
NOMATCH,
POSSIBLE,
MATCH
}
private boolean matchActionListWithStackElement(StackElement s,
NVDLElement e,
ActionList al) {
List<NVDLAction> l = al.getActions();
int lastIdx = l.size() - 1;
int idx = lastIdx - 1;
State state = s.state;
for (; s != null; s = s.parent) {
NVDLAction a = s.getAction();
if (a == null) continue;
if (idx < 0) return false;
NVDLAction a2 = l.get(idx);
if (!a.equals(a2)) return false;
idx--;
}
NVDLAction a2 = l.get(lastIdx);
State[] states = state.next(e.parent, e.ns, true);
for (int i = 0; i < states.length; i++) {
if (a2.equals(states[i].action)) return true;
}
return false;
}
public MatchResult matchActionList(NVDLElement nextElement,
ActionList al) {
int size = currentContext.size();
for (int i = 0; i < size; i++) {
StackElement s = currentContext.get(i);
if (matchActionListWithStackElement(s, nextElement, al))
return MatchResult.MATCH;
}
return MatchResult.NOMATCH;
}
public void reset() {
currentContext.clear();
nextContext.clear();
isAttributeAttached = false;
StackElement initialStack = StackElement.newEffectiveStackElement(null, initialState, null, true);
currentContext.add(initialStack);
}
public PDA(NVDLRules rules) {
NVDLMode startMode = rules.getStartMode();
Compiler compiler = new Compiler();
this.initialState = compiler.compile(startMode);
reset();
}
public PDA(PDA base) {
this.initialState = base.initialState;
reset();
}
// --------------------------------------------------------------------------------
// compilation part
// --------------------------------------------------------------------------------
private static class Compiler {
static class StateDicKey {
private NVDLMode mode;
private NVDLAction action;
public boolean equals(Object o) {
if (!(o instanceof StateDicKey)) return false;
StateDicKey s = (StateDicKey) o;
return mode.equals(s.mode) && action.equals(s.action);
}
public int hashCode() {
if (action == null) {
return mode.hashCode();
} else {
return mode.hashCode() ^ action.hashCode();
}
}
StateDicKey(NVDLMode mode, NVDLAction action) {
this.mode = mode;
this.action = action;
}
}
// StateDicKey -> State
private HashMap<StateDicKey, State> stateDic = new HashMap<StateDicKey, State>();
private State getState(StateDicKey k) {
return stateDic.get(k);
}
private State newState(StateDicKey k) {
State s = new State(k.mode, k.action);
stateDic.put(k, s);
return s;
}
private Edge.Mode.Dest compileRule(NVDLRule rule, NVDLMode m) {
NVDLActionManager am = rule.getActionManager();
ArrayList<State> states = new ArrayList<State>();
NVDLResultAction ra = am.getResultAction();
if (ra != null) states.add(compileToState(ra, m));
List nras = am.getNoResultActions();
Iterator it = nras.iterator();
while (it.hasNext()) {
NVDLNoResultAction nra = (NVDLNoResultAction) it.next();
states.add(compileToState(nra, m));
}
return new Edge.Mode.Dest(rule,
states.toArray(new State[states.size()]));
}
private Edge.Mode compileToMode(NVDLMode m) {
Edge.Mode em = new Edge.Mode();
NVDLRule rule;
ArrayList<Edge.Mode.Dest> dests = new ArrayList<Edge.Mode.Dest>();
Iterator it = m.notAnyNamespaceRuleIterator();
while (it.hasNext()) {
rule = (NVDLRule) it.next();
Edge.Mode.Dest d = compileRule(rule, m);
dests.add(d);
}
rule = m.getAnyNamespaceRuleForAttribute();
if (rule != null) {
Edge.Mode.Dest d = compileRule(rule, m);
dests.add(d);
}
rule = m.getAnyNamespaceRuleForElement();
if (rule != null) {
Edge.Mode.Dest d = compileRule(rule, m);
dests.add(d);
}
em.dests = (Edge.Mode.Dest[]) dests.toArray(new Edge.Mode.Dest[dests.size()]);
return em;
}
private Edge compileToDefaultEdge(NVDLMode m) {
Edge e = new Edge(null, compileToMode(m));
return e;
}
private Edge[] compileToContextEdges(NVDLAction a) {
List<NVDLAction.Context> contextsList = a.getContextsList();
Edge[] contextEdges = new Edge[contextsList.size()];
int i = 0;
Iterator<NVDLAction.Context> it = contextsList.iterator();
while (it.hasNext()) {
NVDLAction.Context c = it.next();
contextEdges[i++] = new Edge(c, compileToMode(c.useMode));
}
return contextEdges;
}
private State compileToState(NVDLAction a, NVDLMode m) {
StateDicKey k = new StateDicKey(m, a);
State s = getState(k);
if (s != null) return s;
s = newState(k);
if (a == null) {
s.defaultEdge = compileToDefaultEdge(m);
} else {
s.contextEdges = compileToContextEdges(a);
s.defaultEdge = compileToDefaultEdge(a.getUseMode());
}
return s;
}
State compile(NVDLMode startMode) {
return compileToState(null, startMode);
}
}
private void dumpDest(Edge.Mode.Dest d, Set<State> traversed) {
System.out.println(d.toString());
for (int i = 0; i < d.nextStates.length; i++) {
dumpState(d.nextStates[i], traversed);
}
}
private void dumpMode(Edge.Mode em, Set<State> traversed) {
for (int i = 0; i < em.dests.length; i++) {
dumpDest(em.dests[i], traversed);
}
}
private void dumpEdge(Edge edge, Set<State> traversed) {
System.out.println(edge.toString());
dumpMode(edge.nextMode, traversed);
}
private void dumpState(State state, Set<State> traversed) {
System.out.println(state.toString());
if (!(traversed.contains(state))) {
traversed.add(state);
dumpEdge(state.defaultEdge, traversed);
for (int i = 0; i < state.contextEdges.length; i++) {
dumpEdge(state.contextEdges[i], traversed);
}
}
System.out.println("--------------------");
}
public void dump() {
dumpState(initialState, new HashSet<State>());
}
}