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