blob: 7b8d059751a6a042458406ba37461edb2e08e587 [file] [log] [blame]
/*
* Copyright 2009-2012 by The Regents of the University of California
* Licensed 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 from
*
* 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 edu.uci.ics.asterix.lexergenerator;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import edu.uci.ics.asterix.lexergenerator.rules.*;
public class LexerNode {
private static String TOKEN_PREFIX = "TOKEN_";
private LinkedHashMap<Rule, LexerNode> actions = new LinkedHashMap<Rule, LexerNode>();
private String finalTokenName;
private Set<String> ongoingParsing = new HashSet<String>();
public LexerNode clone() {
LexerNode node = new LexerNode();
node.finalTokenName = this.finalTokenName;
for (Map.Entry<Rule, LexerNode> entry : this.actions.entrySet()) {
node.actions.put(entry.getKey().clone(), entry.getValue().clone());
}
for (String ongoing : this.ongoingParsing) {
node.ongoingParsing.add(ongoing);
}
return node;
}
public void add(Rule newRule) {
if (actions.get(newRule) == null) {
actions.put(newRule, new LexerNode());
}
}
public void append(Rule newRule) {
if (actions.size() == 0) {
add(newRule);
} else {
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
action.getValue().append(newRule);
}
if (actions.containsKey(new RuleEpsilon())) {
actions.remove(new RuleEpsilon());
add(newRule);
}
}
}
public void merge(LexerNode newNode) throws Exception {
for (Map.Entry<Rule, LexerNode> action : newNode.actions.entrySet()) {
if (this.actions.get(action.getKey()) == null) {
this.actions.put(action.getKey(), action.getValue());
} else {
this.actions.get(action.getKey()).merge(action.getValue());
}
}
if (newNode.finalTokenName != null) {
if (this.finalTokenName == null) {
this.finalTokenName = newNode.finalTokenName;
} else {
throw new Exception("Rule conflict between: " + this.finalTokenName + " and " + newNode.finalTokenName);
}
}
for (String ongoing : newNode.ongoingParsing) {
this.ongoingParsing.add(ongoing);
}
}
public void append(LexerNode node) throws Exception {
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
if (action.getKey() instanceof RuleEpsilon)
continue;
action.getValue().append(node);
}
if (actions.containsKey(new RuleEpsilon())) {
actions.remove(new RuleEpsilon());
merge(node.clone());
}
if (actions.size() == 0 || finalTokenName != null) {
finalTokenName = null;
merge(node.clone());
}
}
public void appendTokenName(String name) {
if (actions.size() == 0) {
this.finalTokenName = name;
} else {
ongoingParsing.add(TOKEN_PREFIX + name);
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
action.getValue().appendTokenName(name);
}
}
}
public LexerNode removeTokensName() {
this.finalTokenName = null;
this.ongoingParsing.clear();
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
action.getValue().removeTokensName();
}
return this;
}
public String toString() {
StringBuilder result = new StringBuilder();
if (finalTokenName != null)
result.append("! ");
if (actions.size() == 1)
result.append(actions.keySet().toArray()[0].toString() + actions.values().toArray()[0].toString());
if (actions.size() > 1) {
result.append(" ( ");
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
if (result.length() != 3) {
result.append(" || ");
}
result.append(action.getKey().toString());
result.append(action.getValue().toString());
}
result.append(" ) ");
}
return result.toString();
}
public String toJava() {
StringBuffer result = new StringBuffer();
if (numberOfRuleChar() > 2) {
result.append(toJavaSingleCharRules());
result.append(toJavaComplexRules(false));
} else {
result.append(toJavaComplexRules(true));
}
if (this.finalTokenName != null) {
result.append("return " + TOKEN_PREFIX + finalTokenName + ";\n");
} else if (ongoingParsing != null) {
String ongoingParsingArgs = collectionJoin(ongoingParsing, ',');
result.append("return parseError(" + ongoingParsingArgs + ");\n");
}
return result.toString();
}
private int numberOfRuleChar() {
int singleCharRules = 0;
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
if (action.getKey() instanceof RuleChar)
singleCharRules++;
}
return singleCharRules;
}
private String toJavaSingleCharRules() {
StringBuffer result = new StringBuffer();
result.append("switch(currentChar){\n");
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
if (action.getKey() instanceof RuleChar) {
RuleChar rule = (RuleChar) action.getKey();
result.append("case '" + rule.expectedChar() + "':\n");
result.append(rule.javaAction()).append("\n");
result.append(action.getValue().toJava());
}
}
result.append("}\n");
return result.toString();
}
private String toJavaComplexRules(boolean all) {
StringBuffer result = new StringBuffer();
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
if (!all && action.getKey() instanceof RuleChar)
continue;
if (action.getKey() instanceof RuleEpsilon)
continue;
String act = action.getKey().javaAction();
if (act.length() > 0) {
act = "\n" + act;
}
result.append(action.getKey().javaMatch(act + "\n" + action.getValue().toJava()));
}
return result.toString();
}
public void expandFirstAction(LinkedHashMap<String, Token> tokens) throws Exception {
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
Rule first = action.getKey();
if (first instanceof RulePartial) {
if (tokens.get(((RulePartial) first).getPartial()) == null) {
throw new Exception("Cannot find a token used as part of another definition, missing token: "
+ ((RulePartial) first).getPartial());
}
actions.remove(first);
LexerNode node = tokens.get(((RulePartial) first).getPartial()).getNode().clone();
merge(node);
}
}
}
public Set<String> neededAuxFunctions() {
HashSet<String> partials = new HashSet<String>();
for (Map.Entry<Rule, LexerNode> action : actions.entrySet()) {
Rule rule = action.getKey();
if (rule instanceof RulePartial) {
partials.add(((RulePartial) rule).getPartial());
}
partials.addAll(action.getValue().neededAuxFunctions());
}
return partials;
}
public String toJavaAuxFunction() {
String oldFinalTokenName = finalTokenName;
if (oldFinalTokenName == null)
finalTokenName = "AUX_NOT_FOUND";
String result = toJava();
finalTokenName = oldFinalTokenName;
return result;
}
private String collectionJoin(Collection<String> collection, char c) {
StringBuilder ongoingParsingArgs = new StringBuilder();
for (String token : collection) {
ongoingParsingArgs.append(token);
ongoingParsingArgs.append(c);
}
if (ongoingParsing.size() > 0) {
ongoingParsingArgs.deleteCharAt(ongoingParsingArgs.length() - 1);
}
return ongoingParsingArgs.toString();
}
}