/** * 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.rules; import jlibs.nblr.matchers.Matcher; import java.util.*; /** * @author Santhosh Kumar T */ public class Path extends ArrayList<Object>{ public Path(Deque<Object> stack){ super(stack); Collections.reverse(this); } public Edge matcherEdge(){ for(int i=size()-1; i>=0; i--){ Object obj = get(i); if(obj instanceof Edge){ Edge edge = (Edge)obj; if(edge.matcher!=null) return edge; } } return null; } @SuppressWarnings({"SimplifiableConditionalExpression"}) public boolean fallback(){ for(Object obj: this){ if(obj instanceof Edge){ Edge edge = (Edge)obj; if((edge.matcher!=null || edge.ruleTarget!=null) && edge.fallback) return true; } } return false; } public Matcher matcher(){ Edge matcherEdge = matcherEdge(); return matcherEdge!=null ? matcherEdge.matcher : null; } public boolean clashesWith(Path that){ if(this.depth!=that.depth) throw new IllegalArgumentException("depths are not same: "+this.depth+"!="+that.depth); if(depth>1){ if(!this.parent.clashesWith(that.parent)) return false; } return this.matcher().clashesWith(that.matcher()); } public Paths children; public Path parent; public int depth; public int branch; public boolean hasLoop(){ Node lastNode = (Node)get(size()-1); if(subList(0, size()-1).contains(lastNode)) return true; Path path = parent; while(path!=null){ if(path.contains(lastNode)) return true; path = path.parent; } return false; } public Path[] route(){ List<Path> route = new LinkedList<Path>(); Path p = this; while(p!=null){ route.add(0, p); p = p.parent; } return route.toArray(new Path[route.size()]); } public Node nodeAfterPop(){ int rulesPopped = 0; Node target = null; Path p = this; while(p!=null && target==null){ boolean wasNode = false; for(int i=p.size()-1; i>=0; i--){ Object obj = p.get(i); if(obj instanceof Node){ if(wasNode) rulesPopped++; wasNode = true; }else if(obj instanceof Edge){ wasNode = false; Edge edge = (Edge)obj; if(edge.ruleTarget!=null){ if(rulesPopped==0){ target = edge.target; break; }else rulesPopped--; } } } p = p.parent; } return target; } public Node destination(){ return (Node)get(size()-1); } public void travelWithoutMatching(){ while(true){ Node node = destination(); if(node.junction() || (node.name!=null && !node.name.equals(Node.DYNAMIC_STRING_MATCH))) return; switch(node.outgoing.size()){ case 1: Edge edge = node.outgoing.get(0); if(edge.matcher==null && edge.ruleTarget==null){ add(edge); add(edge.target); break; }else if(edge.ruleTarget!=null){ // travel only one rule target add(edge); add(edge.ruleTarget.node()); return; }else return; default: return; } } } @Override public String toString(){ String str; Matcher matcher = matcher(); if(matcher==null) str = "<EOF>"; else if(matcher.name!=null) str = '<'+matcher.name+'>'; else str = matcher.toString(); return parent!=null ? parent+str : str; } }