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

jlibs.nblr.codegen.CodeGenerator 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.util.Range;
import jlibs.nblr.Syntax;
import jlibs.nblr.codegen.java.SyntaxClass;
import jlibs.nblr.matchers.Matcher;
import jlibs.nblr.rules.Edge;
import jlibs.nblr.rules.Node;
import jlibs.nblr.rules.Routes;
import jlibs.nblr.rules.Rule;

import java.io.File;
import java.util.*;

/**
 * @author Santhosh Kumar T
 */
public abstract class CodeGenerator{
    public boolean INLINE_RULES = false;

    protected Syntax syntax;
    protected Printer printer;

    public CodeGenerator(Syntax syntax){
        this.syntax = syntax;
    }

    protected boolean debuggable;
    private void inlineRules() throws Exception{
        syntax = syntax.copy();

        File tempFile = new File("temp/temp.syntax");
        Set rulesChecked = new HashSet();

        Iterator rules = syntax.rules.values().iterator();
        while(rules.hasNext()){
            Rule rule = rules.next();
            if(rulesChecked.contains(rule.name))
                continue;

            rulesChecked.add(rule.name);

            boolean hasNodeWithName = false;
            for(Node node: rule.nodes()){
                if(node.name!=null){
                    hasNodeWithName = true;
                    break;
                }
            }
            if(hasNodeWithName)
                continue;

            List usages = syntax.usages(rule);
            if(usages.size()==1 && usages.get(0)!=rule){
                boolean inlined = false;

                Rule usingRule = usages.get(0);
                for(Edge edge: usingRule.edges()){
                    if(edge.ruleTarget!=null && edge.ruleTarget.rule==rule && edge.ruleTarget.name==null && !edge.loop()){
                        edge.inlineRule();
                        inlined = true;
                    }
                }
                if(inlined){
                    rules.remove();
                    syntax.updateRuleIDs();
                    try{
                        for(Node state: usingRule.states())
                            new Routes(usingRule, state);
                        syntax.saveTo(tempFile);
                        //System.out.println("inlined "+rule.name+" in "+usingRule.name);
                    }catch(IllegalStateException ex){
                        syntax = Syntax.loadFrom(tempFile);
                        rules = syntax.rules.values().iterator();
                    }
                }
            }
        }
    }

    protected int stringRuleID = -1;
    private void detectStringRules(){
        startStringIDs();
        syntax = syntax.copy();
        int id = 0;
        for(Rule r: syntax.rules.values()){
            int codePoints[] = r.matchString();
            if(codePoints!=null){
                r.id = stringRuleID--;
                addStringID(codePoints);
            }else
                r.id = id++;
        }
        finishStringIDs();
        printer.emptyLine(true);
        for(Rule rule: syntax.rules.values()){
            if(rule.id<0)
                addRuleID(rule.name, rule.id);
        }
        printer.emptyLine(true);
    }

    private void detectDynamicStringMatches(){
        syntax = syntax.copy();
        for(Rule r: syntax.rules.values()){
            for(Node node: r.nodes()){
                if(Node.DYNAMIC_STRING_MATCH.equals(node.name)){
                    if(node.outgoing.size()!=1)
                        throw new IllegalStateException("Illegal Usage of "+Node.DYNAMIC_STRING_MATCH);
                    Edge edge = node.outgoing.get(0);
                    if(edge.loop())
                        throw new IllegalStateException("Illegal Usage of "+Node.DYNAMIC_STRING_MATCH);
                    if(edge.matcher==null && edge.ruleTarget==null)
                        throw new IllegalStateException("Illegal Usage of "+Node.DYNAMIC_STRING_MATCH);
                    edge.matcher = null;
                    edge.ruleTarget = null;
                }
            }
        }
    }

    public final void generateParser(Printer printer){
        this.printer = printer;
        if(!debuggable){
            try{
                if(INLINE_RULES)
                    inlineRules();
            }catch(Exception ex){
                throw new RuntimeException(ex);
            }
        }

        startParser();
        printer.emptyLine(true);

        SyntaxClass.DEBUGGABLE = debuggable;
        SyntaxClass syntaxClass = new SyntaxClass(syntax);
        syntaxClass.generate(printer);
        syntax = syntaxClass.syntax;

//        if(!debuggable){
//            detectDynamicStringMatches();
//            detectStringRules();
//        }

//        if(syntax.matchers.size()>0){
//            printTitleComment("Matchers");
//            printer.emptyLine(true);
//            for(Matcher matcher: syntax.matchers.values()){
//                printMatcherMethod(matcher);
//                printer.emptyLine(true);
//            }
//        }

//        int maxLookAhead = 0;
//        if(syntax.rules.size()>0){
//            printTitleComment("Rules");
//            printer.emptyLine(true);
//
//            // NOTE: ids of all rules should be computed before calculating Routes
//            for(Rule rule: syntax.rules.values())
//                rule.computeIDS();
//
//            for(Rule rule: syntax.rules.values()){
//                if(rule.id<0)
//                    continue;
//                addRuleID(rule.name, rule.id);
//                startRuleMethod(rule);
//
//                statesVisited.clear();
//                statesPending.clear();
//                statesPending.add(rule.node);
//                while(!statesPending.isEmpty()){
//                    Node state = statesPending.iterator().next();
//                    statesPending.remove(state);
//                    statesVisited.add(state);
//                    try{
//                        Routes routes = new Routes(rule, state);
//                        routes.travelWithoutMatching();
//
//                        startCase(state.id);
//                        if(routes.isEOF())
//                            printer.println("// EOF-State");
//                        addRoutes(routes);
//                        endCase();
//                        maxLookAhead = Math.max(maxLookAhead, routes.maxLookAhead);
//                    }catch(IllegalStateException ex){
//                        throw new IllegalStateException(ex.getMessage()+" in Rule '"+rule.name+"'");
//                    }
//                    if(statesPending.isEmpty()){
//                        for(Node node: rule.nodes()){
//                            if(node.name!=null)
//                                addState(node);
//                        }
//                    }
//                }
//                finishRuleMethod(rule);
//                printer.emptyLine(true);
//            }
//        }
//
//        startCallRuleMethod();
//        for(Rule rule: syntax.rules.values()){
//            if(rule.id>=0){
//                startCase(rule.id);
//                callRuleMethod(rule.name);
//                printer.printlns(MINUS);
//            }
//        }
//        finishCallRuleMethod();

        printer.emptyLine(false);
        finishParser(syntaxClass.maxLookAhead());
    }

    private ArrayList statesVisited = new ArrayList();
    protected LinkedHashSet statesPending = new LinkedHashSet();
    protected void addState(Node state){
        if(!statesVisited.contains(state))
            statesPending.add(state);
    }

    protected abstract void startCase(int id);
    protected abstract void endCase();

    protected abstract void printTitleComment(String title);
    protected abstract void startParser();
    protected abstract void finishParser(int maxLookAhead);

    protected abstract void printMatcherMethod(Matcher matcher);

    protected abstract void addRuleID(String name, int id);
    protected abstract void startRuleMethod(Rule rule);
    protected abstract void addRoutes(Routes routes);
    protected abstract void finishRuleMethod(Rule rule);

    protected abstract void startStringIDs();
    protected abstract void addStringID(int codePoints[]);
    protected abstract void finishStringIDs();

    protected abstract void startCallRuleMethod();
    protected abstract void callRuleMethod(String ruleName);
    protected abstract void finishCallRuleMethod();

    public final void generateConsumer(Printer printer){
        this.printer = printer;

        startHandler();

        Set set = syntax.publishMethods();
        if(set.size()>0){
            printTitleComment("Publishers");
            printer.emptyLine(true);
            for(String publisher: set){
                addPublishMethod(publisher);
                printer.emptyLine(true);
            }
        }

        set = syntax.eventMethods();
        if(set.size()>0){
            printTitleComment("Events");
            printer.emptyLine(true);
            for(String event: set){
                addEventMethod(event);
                printer.emptyLine(true);
            }
        }

        printer.emptyLine(false);
        finishHandler();
    }

    protected abstract void startHandler();
    protected abstract void addPublishMethod(String name);
    protected abstract void addEventMethod(String name);
    protected abstract void finishHandler();

    protected static Matcher eofMatcher = new Matcher(){
        @Override
        public String toString(){ throw new UnsupportedOperationException(); }

        @Override
        protected String __javaCode(String variable){ throw new UnsupportedOperationException(); }

        @Override
        public List ranges(){
            return Collections.emptyList();
        }
    };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy