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

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

import jlibs.core.annotation.processing.Printer;
import jlibs.nblr.Syntax;
import jlibs.nblr.codegen.FinishAllMethod;
import jlibs.nblr.codegen.IfBlock;
import jlibs.nblr.codegen.RuleMethod;
import jlibs.nblr.codegen.State;
import jlibs.nblr.matchers.Any;
import jlibs.nblr.matchers.Matcher;
import jlibs.nblr.matchers.Not;
import jlibs.nblr.rules.Answer;
import jlibs.nblr.rules.Rule;

import java.util.*;

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

/**
 * @author Santhosh Kumar T
 */
public class SyntaxClass{
    public static boolean DEBUGGABLE = false;

    public Syntax syntax;
    public List ruleMethods = new ArrayList();

    public SyntaxClass(Syntax syntax){
        this.syntax = syntax.copy();
        if(!DEBUGGABLE){
            detectStringRules();
            syntax = this.syntax;
        }

        boolean recompute;
        do{
            ruleMethods.clear();
            recompute = false;

            // 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){
                    RuleMethod ruleMethod;
                    while(true){
                        ruleMethod = new RuleMethod(this, rule);
                        if(DEBUGGABLE || !ruleMethod.deleteEmptySwitches())
                            break;
                        else
                            recompute = true;
                    }
                    ruleMethods.add(ruleMethod);
                }
            }
        }while(recompute);

        syntax.computeBufferingStates();

        for(RuleMethod ruleMethod: ruleMethods){
            for(State state: ruleMethod.states){
                IfBlock first = state.ifBlocks.get(0);
                if(first.usesFinishAll()){
                    FinishAllMethod method = addToFinishAll(first.matcher);
                    Answer ans = state.fromNode.buffering;
                    if(method.buffering==null)
                        method.buffering = ans;
                    else if(method.buffering!=ans)
                        method.buffering = Answer.MAY_BE;
                    if(first.finishAllReturnValueRequired())
                        method.returnValueRequired = true;
                }
            }
        }

        /*
        // print no of continues used for each rule
        for(RuleMethod ruleMethod: ruleMethods){
            int count = 0;
            for(int i=0; i stringRules = new ArrayList();
    private void detectStringRules(){
        syntax = syntax.copy();

        int stringRuleID = -1;
        int id = 0;
        for(Rule r: syntax.rules.values()){
            int codePoints[] = r.matchString();
            if(codePoints!=null){
                r.id = stringRuleID--;
                stringRules.add(r);
            }else
                r.id = id++;
        }
    }

    private int unnamed_finishAllMethods = 0;
    private Map finishAllMethods = new LinkedHashMap();
    public static final String FINISH_ALL = "finishAll";
    public static final String FINISH_ALL_OTHER_THAN = "finishAll_OtherThan";
    public FinishAllMethod addToFinishAll(Matcher matcher){
        boolean not = false;
        Matcher givenMatcher = matcher;
        if(matcher instanceof Not){
            not = true;
            matcher = ((Not)matcher).delegate;
        }
        if(matcher instanceof Any){
            Any any = (Any)matcher;
            if(any.chars!=null && any.chars.length==1)
                return new FinishAllMethod(matcher, not ? FINISH_ALL_OTHER_THAN : FINISH_ALL);
        }
        matcher = givenMatcher;

        FinishAllMethod method = null;
        if(matcher.name!=null)
            method = finishAllMethods.get(matcher);
        else{
            for(Map.Entry entry: finishAllMethods.entrySet()){
                if(entry.getKey().same(matcher)){
                    method = entry.getValue();
                    break;
                }
            }
        }
        if(method==null){
            String name = matcher.name;
            if(name==null)
                name = String.valueOf(++unnamed_finishAllMethods);
            method = new FinishAllMethod(matcher, name);
            finishAllMethods.put(matcher, method);
        }
        return method;
    }

    public void generate(Printer printer){
        if(!DEBUGGABLE)
            generateStringRules(printer);
        generateMatcherMethods(printer);
        generaleRuleMethods(printer);
        generateFinishAllMethods(printer);
        generateCallRuleMethod(printer);
    }

    private void generaleRuleMethods(Printer printer){
        if(ruleMethods.size()>0){
            printer.titleComment("Rules");
            for(RuleMethod ruleMethod: ruleMethods){
                ruleMethod.generate(printer);
                printer.emptyLine(true);
            }
        }
    }

    private void generateFinishAllMethods(Printer printer){
        for(FinishAllMethod method: finishAllMethods.values()){
            printer.emptyLine(true);
            method.generate(printer);
        }
    }

    private void generateStringRules(Printer printer){
        printer.printlns(
            "private static final int STRING_IDS[][] = {",
                PLUS,
                "{}, // dummy one"
        );

        for(Rule rule: syntax.rules.values()){
            if(rule.id<0){
                int[] codePoints = rule.matchString();
                String str = Arrays.toString(codePoints);

                printer.print("{");
                printer.print(str.substring(1, str.length()-1));
                printer.print("}, // ");
                printer.println(new String(codePoints, 0, codePoints.length));
            }
        }

        printer.printlns(
                MINUS,
            "};"
        );

        printer.emptyLine(true);
        for(Rule rule: syntax.rules.values()){
            if(rule.id<0)
                printer.println("public static final int RULE_"+rule.name.toUpperCase()+" = "+rule.id+';');
        }
    }

    private void generateMatcherMethods(Printer printer){
        if(syntax.matchers.size()>0){
            printer.titleComment("Matchers");
            for(Matcher matcher: syntax.matchers.values()){
                if(!matcher.canInline()){
                    printer.printlns(
                        "private static boolean "+matcher.name+"(int ch){",
                            PLUS,
                            "return "+matcher.javaCode("ch")+';',
                            MINUS,
                        "}"
                    );
                    printer.emptyLine(true);
                }
            }
        }
    }

    private void generateCallRuleMethod(Printer printer){
        printer.emptyLine(true);
        printer.printlns(
            "@Override",
            "protected final boolean callRule(int rule, int state) throws Exception{",
                PLUS,
                "if(SHOW_STATS)",
                    PLUS,
                    "callRuleCount++;",
                    MINUS
        );
        if(!DEBUGGABLE){
            printer.printlns(
                    "if(rule<0){",
                        PLUS,
                        "if(rule==RULE_DYNAMIC_STRING_MATCH)",
                            PLUS,
                            "return matchString(state, dynamicStringToBeMatched);",
                            MINUS,
                        "else",
                            PLUS,
                            "return matchString(rule, state, STRING_IDS[-rule]);",
                            MINUS,
                        MINUS,
                    "}"
            );
        }
        printer.printlns(
                    "switch(rule){",
                        PLUS
        );

        for(Rule rule: syntax.rules.values()){
            if(rule.id>=0){
                printer.printlns(
                    "case "+rule.id+":",
                        PLUS,
                        "return "+rule.name+"(state);",
                        MINUS
                );
            }
        }
        printer.printlns(
                    "default:",
                        PLUS,
                        "throw new Error(\"impossible rule: \"+stack[free-2]);",
                        MINUS,
                    MINUS,
                "}",
                MINUS,
            "}"
        );
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy