All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jlibs.nblr.rules.Paths Maven / Gradle / Ivy

/**
 * 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 java.util.*;

/**
 * @author Santhosh Kumar T
 */
public class Paths extends ArrayList{
    public final Path owner;
    public final int depth;

    public Paths(Path owner){
        this.owner = owner;
        if(owner!=null){
            owner.children = this;
            depth = owner.depth+1;
        }else
            depth = 1;
    }

    public boolean add(Path path){
        if(owner==null)
            path.branch = size();
        else
            path.branch = owner.branch;

        path.parent = owner;
        path.depth = depth;
        return super.add(path);
    }

    public List leafs(){
        List list = new ArrayList();
        leafs(list);
        return list;
    }
    
    private void leafs(List list){
        for(Path path: this){
            if(path.children==null)
                list.add(path);
            else
                path.children.leafs(list);
        }
    }

    @SuppressWarnings({"SimplifiableIfStatement"})
    private static boolean clashes(Path p1, Path p2){
        if(p1.matcher()==null && p2.matcher()==null)
            throw new IllegalStateException("Ambiguous Routes: "+p1+" AND "+p2);
        if(p1.matcher()!=null && p2.matcher()!=null){
            if(p1.fallback() || p2.fallback())
                return false;
            else
                return p1.clashesWith(p2);
        }
        return false;
    }

    public static Paths travel(Node fromNode, boolean digIntoRule){
        Paths rootPaths = new Paths(null);
        List list = new ArrayList();

        while(true){
            if(list.size()==0){
                rootPaths.populate(fromNode, digIntoRule);
                list.addAll(rootPaths);
            }else{
                List newList = new ArrayList();
                for(Path path: list){
                    if(path.matcher()!=null){
                        Paths paths = new Paths(path);
                        paths.populate((Node)path.get(path.size()-1), true);
                        newList.addAll(paths);
                    }
                }
                list = newList;
            }

            TreeSet clashingIndexes = new TreeSet();
            for(int ibranch=0; ibranch clashingPaths = new ArrayList(clashingIndexes.size());
            for(int id: clashingIndexes)
                clashingPaths.add(list.get(id));
            list = clashingPaths;
        }
    }

    private void populate(Node fromNode, boolean digIntoRule){
        populate(fromNode, new ArrayDeque(), digIntoRule);
    }

    private void populate(Node fromNode, Deque stack, boolean digIntoRule){
        if(stack.contains(fromNode))
            throw new IllegalStateException("infinite loop detected");

        stack.push(fromNode);
        if(fromNode.outgoing.size()>0){
            if(fromNode.outgoing.size()>1)
                digIntoRule = true;
            for(Edge edge: fromNode.outgoing){
                stack.push(edge);
                if(edge.matcher!=null){
                    stack.push(edge.target);
                    add(new Path(stack));
                    stack.pop();
                }else if(edge.ruleTarget!=null){
                    if(!digIntoRule){
                        if(new Routes(edge.ruleTarget.rule, edge.ruleTarget.node(), true).routeStartingWithEOF!=null) // the rule can match nothing
                            digIntoRule = true;
                    }
                    if(!digIntoRule){
                        stack.push(edge.ruleTarget.node());
                        add(new Path(stack));
                        stack.pop();
                    } else{
                        populate(edge.ruleTarget.node(), stack, digIntoRule);
                    }
                }else
                    populate(edge.target, stack, digIntoRule);
                stack.pop();
            }
        }else{
            Path temp = new Path(stack);
            temp.parent = this.owner;
            Node target = temp.nodeAfterPop();
            if(target==null)
                add(new Path(stack));
            else
                populate(target, stack, digIntoRule);
        }
        stack.pop();
    }
}