jlibs.nblr.BufferingDepths Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jlibs-nblr Show documentation
Show all versions of jlibs-nblr Show documentation
Non-Blocking Language Recognition
/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package jlibs.nblr;
import jlibs.nblr.actions.BufferAction;
import jlibs.nblr.actions.ErrorAction;
import jlibs.nblr.actions.PublishAction;
import jlibs.nblr.rules.*;
import javax.swing.tree.TreePath;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
/**
* @author Santhosh Kumar T
*/
public class BufferingDepths{
public Map>> ruleMap = new HashMap>>();
private Map depths(RuleTarget ruleTarget, boolean create){
Map> nodeMap = ruleMap.get(ruleTarget.rule);
if(nodeMap==null){
if(!create)
return null;
ruleMap.put(ruleTarget.rule, nodeMap=new HashMap>());
}
Map depthMap = nodeMap.get(ruleTarget.node());
if(depthMap==null){
if(!create)
return null;
nodeMap.put(ruleTarget.node(), depthMap=new HashMap());
}
return depthMap;
}
private Integer get(RuleTarget ruleTarget, int depth){
Map depths = depths(ruleTarget, false);
return depths==null ? null : depths.get(depth);
}
private void set(RuleTarget ruleTarget, int enteringDepth, int exitingDepth){
Map depths = depths(ruleTarget, true);
Integer value = depths.get(enteringDepth);
if(value!=null && !value.equals(exitingDepth))
throw new Error(ruleTarget+"["+enteringDepth+"] "+value+", "+exitingDepth);
depths.put(enteringDepth, exitingDepth);
}
private Deque stack = new ArrayDeque();
private TreePath path;
public void calculate(Rule rule){
stack.clear();
path = null;
RuleTarget ruleTarget = new RuleTarget();
ruleTarget.rule = rule;
Edge edge = new Edge(new Node(), new Node());
edge.ruleTarget = ruleTarget;
stack.push(new TreePath(new Element(edge, 0)));
if(rule.node.outgoing.isEmpty()){
process(rule.node, 0);
return;
}
add(rule.node.outgoing.get(0));
outer: while(path!=null){
Element elem = (Element)path.getLastPathComponent();
Edge next = null;
if(elem.edge.ruleTarget!=null){
if(elem.processRuleTarget){
elem.processRuleTarget = false;
Integer exitDepth = get(elem.edge.ruleTarget, elem.depth);
if(exitDepth==null){
Node node = elem.edge.ruleTarget.node();
if(node.outgoing.isEmpty())
process(node, elem.depth);
else{
stack.push(path);
next = node.outgoing.get(0);
}
}
}else
stack.pop();
}
if(next==null)
next = findEdge(null, elem.edge.target);
if(next==null && elem.edge.target.outgoing.size()==0)
process(elem.edge.target, elem.depth);
while(next==null && path!=null){
if(stack.peek()==path)
continue outer;
elem = (Element)path.getLastPathComponent();
next = findEdge(elem.edge, elem.edge.source);
path = path.getParentPath();
}
if(next==null)
return;
else
add(next);
}
}
private void process(Node node, int depth){
depth = update(depth, node);
if(node.action instanceof ErrorAction)
return;
Element e = (Element)stack.peek().getLastPathComponent();
set(e.edge.ruleTarget, e.depth, depth);
}
private int update(int depth, Node node){
if(node.action instanceof BufferAction)
depth++;
else if(node.action instanceof PublishAction){
depth--;
if(depth<0)
throw new IllegalStateException("invalid buffer state");
}
Answer ans = depth>0 ? Answer.YES : Answer.NO;
if(node.buffering==null)
node.buffering = ans;
else if(node.buffering!=ans)
node.buffering = Answer.MAY_BE;
return depth;
}
private void add(Edge edge){
int depth = 0;
if(path!=null){
Element lastElem = (Element)path.getLastPathComponent();
if(lastElem.edge.ruleTarget==null)
depth = lastElem.depth;
else if(lastElem.edge.ruleTarget.node()==edge.source)
depth = lastElem.depth;
else{
Integer exitingDepth = get(lastElem.edge.ruleTarget, lastElem.depth);
if(exitingDepth!=null) // null in case of recursion
depth = exitingDepth;
}
}
depth = update(depth, edge.source);
Element elem = new Element(edge, depth);
if(path==null)
path = new TreePath(elem);
else
path = path.pathByAddingChild(elem);
}
private Edge findEdge(Edge curEdge, Node node){
int index = 0;
if(curEdge!=null)
index = node.outgoing.indexOf(curEdge)+1;
for(;index
© 2015 - 2025 Weber Informatics LLC | Privacy Policy