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

jlibs.nblr.codegen.IfBlock 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.codegen;

import jlibs.core.annotation.processing.Printer;
import jlibs.core.lang.StringUtil;
import jlibs.nblr.actions.ErrorAction;
import jlibs.nblr.actions.EventAction;
import jlibs.nblr.actions.PublishAction;
import jlibs.nblr.codegen.java.SyntaxClass;
import jlibs.nblr.matchers.Any;
import jlibs.nblr.matchers.Matcher;
import jlibs.nblr.matchers.Range;
import jlibs.nblr.rules.*;
import jlibs.nbp.NBParser;

import java.util.ArrayList;
import java.util.Iterator;
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 IfBlock implements Iterable{
    public Matcher matcher;
    public Path path;
    protected int common = -1;

    public final State state;
    public final RootIf root;
    public IfBlock parent;
    public final List children = new ArrayList();

    public IfBlock(State state){
        this.state = state;
        root = state.rootIF==null ? (RootIf)this : state.rootIF;
    }

    @Override
    public Iterator iterator(){
        return new Iterator(){
            IfBlock block;

            private IfBlock getNext(){
                if(block==null)
                    return IfBlock.this;
                if(block.children.size()>0){
                    return block.children.get(0);
                }else{
                    IfBlock block = this.block;
                    IfBlock next = null;
                    while(block!=null){
                        List siblings = block.siblings();
                        int index = siblings.indexOf(block);
                        if(index+10){
                depth++;
                height = Math.max(height, depth);
                block = block.children.get(0);
            }else{
                IfBlock next = null;
                while(block.parent!=null){
                    int index = block.parent.children.indexOf(block);
                    if(index+1 siblings(){
        return parent==null ? state.ifBlocks : parent.children;
    }

    private String blockStatement(boolean heightDecreased){
        List siblings = siblings();
        int index = siblings.indexOf(this);
        if(state.ifBlocks.get(0).usesFinishAll())
            index--;

        String blockStmt = "";
        if(index!=0 && !root.lookAheadRequired())
            blockStmt = "else";
        if(matcher!=null){
            if(blockStmt.length()>0)
                blockStmt += " ";
            String ch = "ch";
            if(heightDecreased || !children.isEmpty()){
                int depth = depth();
                if(state.rootIF.lookAheadChars()){
                    if(!heightDecreased)
                        ch = depth==0 ?  "input[position]" : "input[position+"+depth+"]";
                }else
                    ch = "la["+depth+"]";
            }
            blockStmt += "if("+condition(matcher, ch)+")";
        }
        return blockStmt.length()==0 ? null : blockStmt;
    }

    protected void generateChildren(Printer printer, State next){
        if(common!=-1)
            children.get(0).travelPath(printer, 0, common);
        for(IfBlock child: children)
            child.generate(printer, next);
    }
    
    public void generate(Printer printer, State next){
        if(usesFinishAll()){
            useFinishAll(printer);
            return;
        }

        boolean closeLaLenCheck = false;
        boolean heightDecreased = false;
        if(parent==null){
            int index = state.ifBlocks.indexOf(this);
            int prevHeight = index==0 ? 1 : state.ifBlocks.get(index-1).height();
            int curHeight = height();

            if(curHeight>prevHeight){
                if(prevHeight==1){
                    if(root.lookAheadChars())
                        printer.printlns("int "+state.rootIF.available()+" = limit-position+(marker==EOF ? 1 : 0);");
                    else
                        printer.println("addToLookAhead(ch);");
                }

                if(!root.lookAheadChars())
                    root.fillLookAhead(printer, prevHeight, curHeight);
                closeLaLenCheck = true;
                if(root.lookAheadChars()){
                    String last = "position+"+(curHeight-1);
                    printer.printlns(
                        "if("+root.available()+">="+curHeight+"){",
                            PLUS,
                            "ch = limit=="+last+" ? EOF : input["+last+"];"
                    );
                }else{
                    printer.printlns(
                        "if(laLen=="+curHeight+"){",
                            PLUS
                    );
                }
            }else{
                heightDecreased = curHeight siblings = siblings();
        String blockStmt = blockStatement(heightDecreased);
        if(blockStmt!=null){
            printer.printlns(
                blockStmt+"{",
                    PLUS
            );
        }

        if(path!=null)
            generateBody(printer, next, heightDecreased);
        else
            generateChildren(printer, next);
        
        boolean addExpected = parent == null && siblings.indexOf(this) == siblings.size() - 1 && matcher != null;
        if(blockStmt!=null){
            printer.printlns(MINUS);
            printer.print("}");

            int index = siblings.indexOf(this);
            IfBlock nextIF = index==siblings.size()-1 ? null : siblings.get(index+1);
            String nextBlockStmt = nextIF==null ? null : nextIF.blockStatement(heightDecreased);
            boolean sameLine;
            if(nextBlockStmt==null)
                sameLine = addExpected && !root.lookAheadRequired();
            else
                sameLine = nextBlockStmt.startsWith("else");
            if(!sameLine)
                printer.println();
        }
        if(closeLaLenCheck){
            printer.printlns(MINUS);
            printer.print("}");
            if(root.lookAheadChars()){
                printer.printlns(
                    "else if(marker==EOC)",
                        PLUS,
                        state.breakStatement(),
                        MINUS
                );
            }else
                printer.println();
        }
        
        if(addExpected){
            if(!root.lookAheadRequired())
                printer.print("else ");
            printer.println("throw expected(ch, \""+ StringUtil.toLiteral(state.expected(), false)+"\");");
        }
    }

    private Edge edgeWithRule(){
        for(Object obj : path){
            if(obj instanceof Edge){
                Edge edge = (Edge) obj;
                if(edge.ruleTarget != null)
                    return edge;
            }
        }
        return null;
    }

    private String ruleID(Edge edgeWithRule){
        String ruleName = edgeWithRule.ruleTarget.rule.name;
        if(!SyntaxClass.DEBUGGABLE && Node.DYNAMIC_STRING_MATCH.equals(edgeWithRule.source.name))
            ruleName = "DYNAMIC_STRING_MATCH";
        return "RULE_"+ruleName.toUpperCase();
    }

    private String methodCall(Edge edgeWithRule){
        int id = edgeWithRule.ruleTarget.node().stateID;
        
        String methodCall;
        if(!SyntaxClass.DEBUGGABLE && Node.DYNAMIC_STRING_MATCH.equals(edgeWithRule.source.name))
            methodCall = "matchString("+id+", dynamicStringToBeMatched)";
        else{
            Rule rule = edgeWithRule.ruleTarget.rule;
            if(rule.id<0)
                methodCall = "matchString(RULE_"+rule.name.toUpperCase()+", "+id+", STRING_IDS[-RULE_"+rule.name.toUpperCase()+"])";
            else
                methodCall = rule.name+"("+id+")";
        }
        return methodCall;
    }

    private void setState(Printer printer, Node node){
        if(path.get(0)!=node)
            printer.println("state = "+node.stateID+";");
    }

    private boolean addContinue(State next, Node returnNode){
        return root.lookAheadRequired() || next==null || returnNode!=next.fromNode;
    }
    
    private void generateBody(Printer printer, State next, boolean heightDecreased){
        int common = parent==null ? root.common : parent.common;
        int check = travelPath(printer, common+1, path.size()-1);

        if(check==CHECK_ERROR)
            return;
        
        if(parent!=null || heightDecreased){
            if(!root.lookAheadChars())
                printer.println("resetLookAhead();");
        }

        Edge edgeWithRule = edgeWithRule();

        if(edgeWithRule==null){

            Node returnNode = (Node)path.get(path.size()-1);
            if(returnNode.outgoing.size()==0){
                printer.println("return "+(check==CHECK_STOP?"!stop":"true")+";");
            }else{
                setState(printer, returnNode);
                if(check==CHECK_STOP)
                    printer.printlnIf("stop", state.breakStatement());
                else if(check==CHECK_POP)
                    printer.printlnIf("pop", "return true;");
                if(addContinue(next, returnNode))
                    printer.println("continue;");
            }
        }else{
            Node returnNode = edgeWithRule.target;
            boolean doReturn = new Routes(state.ruleMethod.rule, returnNode).isEOF();
            if(!doReturn)
                setState(printer, returnNode);

            if(check==CHECK_STOP){
                printer.printlns(
                    "if(stop){",
                        PLUS,
                        "exiting("+ruleID(edgeWithRule)+", "+edgeWithRule.ruleTarget.node().stateID+");",
                        doReturn ? "return false;" : state.breakStatement(),
                        MINUS,
                    "}else"
                );
            }else if(check==CHECK_POP)
                printer.printlnIf("pop", "return true;");

            if(doReturn){
                printer.println("return "+methodCall(edgeWithRule)+";");
            }else{
                List ifBody = new ArrayList();
                if(addContinue(next, returnNode))
                    ifBody.add("continue;");

                List elseBody = new ArrayList();
                elseBody.add(state.breakStatement());

                if(ifBody.size()==0)
                    printer.printlnIf("!"+methodCall(edgeWithRule), elseBody);
                else
                    printer.printlnIf(methodCall(edgeWithRule), ifBody, elseBody);
            }
        }
    }

    private static int CHECK_STOP = 1;
    private static int CHECK_POP = 2;
    private static int CHECK_ERROR = 3;
    public int travelPath(Printer printer, int from, int to){
        int check = 0;

        for(int index=0; index=from && index<=to){
                            if(SyntaxClass.DEBUGGABLE)
                                printer.println("handler.execute("+state.ruleMethod.rule.id+", "+node.id+");");
                            else
                                printer.println(node.action.javaCode()+';');
                        }
                        if(node.action instanceof EventAction || node.action instanceof PublishAction){
                            if(node.action.toString().startsWith("#"))
                                check = CHECK_STOP;
                            else if(node.action.toString().startsWith("!"))
                                check = CHECK_POP;
                        }else if(node.action instanceof ErrorAction)
                            return CHECK_ERROR;
                    }
                }
            }else if(obj instanceof Edge){
                if(!(index>=from && index<=to))
                    continue;
                Edge edge = (Edge)obj;
                if(edge.ruleTarget!=null){
//                    RuleTarget ruleTarget = edge.ruleTarget;
//                    int idAfterRule = idAfterRule(edge);
//                    String ruleName = ruleName(edge);
//                    printer.println("push(RULE_"+ruleName.toUpperCase()+", "+idAfterRule+", "+id(ruleTarget.node())+");");
                }else if(edge.matcher!=null){
                    if(parent==null){
                        if(!matcher.clashesWith(Range.SUPPLIMENTAL) && !matcher.clashesWith(Any.NEW_LINE))
                            consumeDirectly(printer, edge);
                        else
                            printer.println("consume(ch);"); //"+edge.source.buffering);
                    }else{
                        if(root.lookAheadChars())
                            consumeDirectly(printer, edge);
                        else
                            printer.println("consume(FROM_LA);"); //"+edge.source.buffering);
                    }
                }
            }
        }
        return check;
    }

    private void consumeDirectly(Printer printer, Edge edge){
        if(edge.source.buffering== Answer.NO)
            printer.println("position++;");
        else if(edge.source.buffering==Answer.YES)
            printer.println("buffer.append(input[position++]);");
        else{
            printer.printlns(
                "if(buffer.isBuffering())",
                    PLUS,
                    "buffer.append(input[position]);",
                    MINUS,
                "position++;"
            );
        }
    }

    /*-------------------------------------------------[ FinishAll ]---------------------------------------------------*/
    
    public boolean usesFinishAll(){
        return parent==null && state.ifBlocks.get(0)==this && path!=null && path.size()>1 && edgeWithRule()==null && path.get(0)==path.get(path.size()-1);
    }

    public boolean finishAllReturnValueRequired(){
        for(int i=1; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy