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

jlibs.nblr.codegen.State Maven / Gradle / Ivy

There is a newer version: 3.0.1
Show newest version
/**
 * 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.codegen;

import jlibs.core.annotation.processing.Printer;
import jlibs.core.lang.ArrayUtil;
import jlibs.core.lang.ImpossibleException;
import jlibs.core.lang.StringUtil;
import jlibs.core.util.Range;
import jlibs.nblr.codegen.java.SyntaxClass;
import jlibs.nblr.matchers.Matcher;
import jlibs.nblr.rules.Node;
import jlibs.nblr.rules.Path;
import jlibs.nblr.rules.Routes;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;

import static jlibs.core.annotation.processing.Printer.MINUS;
import static jlibs.core.annotation.processing.Printer.PLUS;

/**
 * @author Santhosh Kumar T
 */
public class State{
    public final RuleMethod ruleMethod;
    public Node fromNode;
    public final List decisions = new ArrayList();

    public final RootIf rootIF = new RootIf(this);
    public final List ifBlocks = rootIF.children;

    public State(RuleMethod ruleMethod, Node fromNode){
        this.ruleMethod = ruleMethod;
        this.fromNode = fromNode;

        Routes routes = new Routes(ruleMethod.rule, fromNode, true);
        
        if(routes.toString().endsWith("[)]"))
            System.out.print("");
        for(int lookAhead: routes.lookAheads())
            processLookAhead(routes.determinateRoutes(lookAhead));

        // move loop without fallback to the beginning
        for(Decision decision: decisions){
            if(decision.usesFinishAll()){
                ruleMethod.syntaxClass.addToFinishAll(decision.matchers[0]);
                decisions.remove(decision);
                decisions.add(0, decision);
                break;
            }
        }

        if(routes.indeterminateRoute!=null)
            decisions.add(new Decision(this, routes.indeterminateRoute.route()[0]));

        if(routes.routeStartingWithEOF!=null)
            decisions.add(new Decision(this, routes.routeStartingWithEOF));

        optimize();
        populateIfBlocks();
    }

    private void processLookAhead(List routes){
        processLookAhead(routes, 1);
    }

    private void processLookAhead(List routes, int depth){
        List> groups = new ArrayList>();
        Matcher matcher = null;
        for(Path route: routes){
            Path path = route.route()[depth-1];
            Matcher curMatcher = path.matcher();
            if(curMatcher==null)
                curMatcher = eofMatcher;

            if(matcher==null || !curMatcher.same(matcher)){
                groups.add(new ArrayList());
                matcher = curMatcher;
            }
            groups.get(groups.size()-1).add(route);
        }

        for(List group: groups){
            Path route = group.get(0);
            if(depth> lists = new ArrayList>();
        for(int i=decisions.size()-1; i>=0; i--){
            Decision decision = decisions.get(i);
            if(decision.path.matcher()==null && isCandidate(decision)){
                boolean listFound = false;
                for(List list: lists){
                    if(decision.path.equals(list.get(0).path)){
                        listFound = true;
                        list.add(decision);
                        break;
                    }
                }
                if(!listFound){
                    List newList = new ArrayList();
                    newList.add(decision);
                    lists.add(newList);
                }
            }
        }
        if(lists.size()==0)
            return;

        if(decisions.get(decisions.size()-1).matchers[0]==null){
            Decision lastDecision = decisions.get(decisions.size()-1);
            for(List list: lists){
                if(list.get(0).path.equals(lastDecision.path)){
                    lists.clear();
                    lists.add(list);
                    break;
                }
            }
        }

        List preferredList = lists.get(0);
        for(int i=1; i list = lists.get(i);
            if(list.size()>preferredList.size())
                preferredList = list;
        }

        Decision preferredDecision = preferredList.get(0);
        if(preferredList.size()==1 && preferredDecision.matchers.length statesVisited, LinkedHashSet statesPending){
        for(Decision decision: decisions)
            decision.computeNextStates(statesVisited, statesPending);
    }

    private void populateIfBlocks(){
        List> lists = new ArrayList>();
        int lastLen = 0;

        for(Decision decision: decisions){
            IfBlock curIf = null;
            if(lastLen!=decision.matchers.length){
                lists.add(new ArrayList());
                lastLen = decision.matchers.length;
            }

            for(Matcher matcher: decision.matchers){
                List children = curIf==null ? lists.get(lists.size()-1) : curIf.children;
                IfBlock found = null;
                if(matcher!=null){
                    for(IfBlock child: children){
                        if(matcher.same(child.matcher)){
                            found = child;
                            break;
                        }
                    }
                }
                if(found==null){
                    found = new IfBlock(this);
                    found.matcher = matcher;
                    children.add(found);
                    found.parent = curIf;
                }
                curIf = found;
            }
            curIf.path = decision.path;
        }

        for(List list: lists)
            rootIF.children.addAll(list);

        rootIF.computeCommon();
    }

    public boolean readCodePoint(){
        for(Decision decision: decisions){
            if(decision.readCodePoint())
                return true;
        }
        return false;
    }

    public boolean readCharacter(){
        for(Decision decision: decisions){
            if(!decision.readCharacter())
                return false;
        }
        return true;
    }

    public boolean matchesNewLine(){
        for(Decision decision: decisions){
            if(decision.matchesNewLine())
                return true;
        }
        return false;
    }

    public String expected(){
        StringBuilder builder = new StringBuilder();
        for(Decision decision: decisions){
            if(builder.length()>0)
                builder.append(" OR ");
            builder.append(decision.expected());
        }
        return builder.toString();
    }

    public boolean requiresContinue(State nextState){
        for(Decision decision: decisions){
            if(decision.requiresContinue(nextState))
                return true;
        }
        return false;
    }

    public int maxLookAhead(){
        int maxLookAhead = 0;
        for(Decision decision: decisions)
            maxLookAhead = Math.max(maxLookAhead, decision.matchers.length);
        return maxLookAhead;
    }

    public boolean lookAheadRequired(){
        return maxLookAhead()>1;
    }

    public String readMethod(){
        if(!lookAheadRequired() && readCharacter() && !matchesNewLine())
            return "position==limit ? marker : input[position]";
        else
            return "codePoint()";
    }

    public String breakStatement(){
        return ruleMethod.requiresWhile() ? "break loop;" : "break;";
    }

    public void generate(Printer printer, State nextState){
        printer.printlns(
            "case "+fromNode.stateID+":",
                PLUS
        );
        rootIF.generate(printer, nextState);
        printer.printlns(
                MINUS
        );
    }

    public void generate1(Printer printer, State nextState){
        printer.printlns(
            "case "+fromNode.stateID+":",
                PLUS
        );

        if(readCodePoint() && (!decisions.get(0).usesFinishAll() || lookAheadRequired())){
            printer.printlns(
                "if((ch="+readMethod()+")==EOC)"+(SyntaxClass.DEBUGGABLE ? "{" : ""),
                    PLUS
//                    "exiting(RULE_"+ruleMethod.rule.name.toUpperCase()+", "+fromNode.stateID+");"
            );
            if(SyntaxClass.DEBUGGABLE)
                printer.println("handler.currentNode("+ruleMethod.rule.id+", "+fromNode.stateID+");");
            printer.println(breakStatement());
            printer.printlns(
//                    "return false;",
                    MINUS,
                SyntaxClass.DEBUGGABLE ? "}" : null
            );
        }

        boolean lookAheadReqd = lookAheadRequired();
        int lastLookAhead = 0;
        int elseAfterDecision = 1;
        int lastDecisionAction = Decision.ADD_CONTINUE;
        boolean closeLALengthCheck = false;
        for(int i=0; ilastLookAhead){
                elseAfterDecision = 1;
                lastDecisionAction = Decision.ADD_CONTINUE;
                if(decision.usesFinishAll())
                     elseAfterDecision = 2;

                if(lookAheadReqd){
                    if(curLookAhead>1){
                        if(lastLookAhead<=1){
                            printer.println("addToLookAhead(ch);");
                            lastLookAhead = 1;
                        }
                        String prefix, condition;
                        if(curLookAhead==lastLookAhead+1){
                            prefix = "if";
                            condition = "ch!=EOF";
                        }else{
                            prefix = "while";
                            condition = "ch!=EOF && laLen<"+curLookAhead; 
                        }
                        printer.printlns(
                            prefix+"("+condition+"){",
                                PLUS,
                                "if((ch=codePoint())==EOC)",
                                    PLUS,
                                    breakStatement(),
                                    MINUS,
                                "addToLookAhead(ch);",
                                MINUS,
                            "}"
                        );
                    }
                                        
                    closeLALengthCheck = true;
                    if(curLookAhead>1){
                        printer.printlns(
                            "if(laLen=="+curLookAhead+"){",
                                PLUS
                        );
                    }
                }
            }

            boolean closeBlock = false;
            if(!lookAheadReqd && (elseAfterDecision<=0 || lastDecisionAction==Decision.GOTO_NEXT_CASE || lastDecisionAction==Decision.CALL_RULE_AND_NEXT_DECISION)){
                printer.print("else ");
                if(decision.matchers[0]==null){
                    closeBlock = true;
                    printer.printlns(
                        "{",
                            PLUS
                    );
                }
            }

            if(decision.usesFinishAll())
                decision.generate(printer, nextState);
            else{
                Decision prevDecision = i==0 ? null : decisions.get(i-1);
                int common = common(prevDecision, decision);
                for(int j=common; j1){
                    printer.printlns(
                            MINUS,
                        "}"
                    );
                }
            }

            lastLookAhead = curLookAhead;
            elseAfterDecision--;
            lastDecisionAction = decision.returnAction(nextState);
        }

        Decision lastDecision = decisions.get(decisions.size()-1);
        if(lastDecision.matchers[0]!=null){
            if(!lookAheadReqd)
                printer.print("else ");
            printer.println("expected(ch, \""+ StringUtil.toLiteral(expected(), false)+"\");");
        }
        
        printer.printlns(
                MINUS
        );
    }

    private int common(Decision decision1, Decision decision2){
        if(decision1==null || decision2==null)
            return 0;
        if(decision1.matchers.length!=decision2.matchers.length)
            return 0;
        if(decision1.usesFinishAll())
            return 0;

        for(int i=0; i ranges(){
            return Collections.emptyList();
        }
    };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy