/*
* Copyright 2011-2011 Gregory Shrago
*
* 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 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 peg;
import com.intellij.openapi.util.text.StringUtil;
import org.antlr.runtime.tree.Tree;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static peg.GrammarParser.*;
public class GeneratorUtil {
private static final Object NULL = new Object();
public static <T>T getAttribute(Tree node, String attrName, @Nullable T def) {
Tree parent = findTopLevel(node);
if (parent == null) return def;
Tree attr = findAttributeValueNode(findChild(parent, ATTRS), attrName);
Object attrVal = getLiteralValue(attr);
if (attrVal != null) return attr == NULL ? def : (T)attrVal;
Tree root = parent.getParent();
for (int i = parent.getChildIndex(); i>=0; i--) {
Tree child = root.getChild(i);
if (child.getType() == ATTRS) {
Tree attr2 = findAttributeValueNode(child, attrName);
Object attrVal2 = getLiteralValue(attr2);
if (attrVal2 != null &&
attr2.getTokenStartIndex() < node.getTokenStopIndex()) {
return attr2 == NULL ? def : (T)attrVal2;
}
}
}
return def;
}
public static String getAttributeName(Tree node, String value) {
Tree parent = findTopLevel(node);
if (parent == null) return null;
Tree attr = findAttributeByValue(findChild(parent, ATTRS), value);
if (attr != null) return findChild(attr, ID).getText();
Tree root = parent.getParent();
for (int i = parent.getChildIndex(); i>=0; i--) {
Tree child = root.getChild(i);
if (child.getType() == ATTRS) {
attr = findAttributeByValue(child, value);
if (attr != null) return findChild(attr, ID).getText();
}
}
return null;
}
public static Tree findTopLevel(Tree node) {
if (node == null) return node;
while (true) {
Tree parent = node.getParent();
if (parent == null) return node;
if (parent.getType() == 0) return node;
node = parent;
}
}
public static Tree findAttributeValueNode(Tree attrs, String attrName) {
for (Tree tree : getChildren(attrs, ATTR)) {
Tree id = findChild(tree, ID);
if (attrName.equals(id.getText())) {
return tree.getChild(id.getChildIndex() + 1);
}
}
return null;
}
public static Tree findAttributeByValue(Tree attrs, String value) {
for (Tree tree : getChildren(attrs, ATTR)) {
Tree id = findChild(tree, ID);
if (value.equals(getLiteralValue(tree.getChild(id.getChildIndex() + 1)))) {
return tree;
}
}
return null;
}
public static Object getLiteralValue(Tree child) {
if (child == null) return null;
String text = child.getText();
if (child.getType() == STRING) return StringUtil.stripQuotesAroundValue(text);
if (child.getType() == NUMBER) return Integer.parseInt(text);
if (child.getType() == ID) {
if (text.equals("true") || text.equals("false")) return Boolean.parseBoolean(text);
if (text.equals("null")) return NULL;
Object attribute = getAttribute(child.getParent(), text, null);
if (attribute == null) {
// todo look for rule
}
return attribute;
}
return null;
}
public static Tree findChild(Tree node, int type) {
if (node == null) return null;
for (int i = 0, len = node.getChildCount(); i < len; i++) {
Tree child = node.getChild(i);
if (child.getType() == type) return child;
}
return null;
}
public static Tree findChild(Tree node, int type, String text) {
if (node == null) return null;
for (int i = 0, len = node.getChildCount(); i < len; i++) {
Tree child = node.getChild(i);
if ((type < 0 || child.getType() == type) && text.equals(child.getText())) {
return child;
}
}
return null;
}
public static List<Tree> getChildren(Tree node) {
return getChildren(node, -1);
}
public static List<Tree> getChildren(Tree node, int type) {
if (node == null) return Collections.emptyList();
List<Tree> result = null;
for (int i = 0, len = node.getChildCount(); i < len; i++) {
Tree child = node.getChild(i);
if (type < 0 || child.getType() == type) {
if (result == null) result = new ArrayList<Tree>();
result.add(child);
}
}
return result == null? Collections.<Tree>emptyList() : result;
}
public static boolean isTrivialNode(Tree node) {
int type = node.getType();
if (node.getChildCount() == 1 && (type == CHOICE || type == SEQ)) {
Tree child = node.getChild(0);
int ct = child.getType();
return !(ct == STRING || ct == NUMBER || ct == ID); //getAttribute(rule, "doNotCollapse", Boolean.FALSE);
}
return false;
}
public static class Rule {
public static boolean is(Tree node) {
return node != null && node.getType() == RULE;
}
public static List<Tree> list(Tree parent) {
return getChildren(parent, RULE);
}
public static boolean isPrivate(Tree node) {
return is(node) && findChild(node, MODIFIER, "private") != null;
}
public static String name(Tree node) {
final Tree child = is(node)? findChild(node, ID) : null;
return child == null? null : child.getText();
}
public static Tree body(Tree rule) {
return is(rule)? findChild(rule, CHOICE) : null;
}
public static Tree firstNotTrivial(Tree rule) {
for (Tree tree = body(rule); tree != null; tree = tree.getChild(0)) {
if (!isTrivialNode(tree)) return tree;
}
return null;
}
public static <T>T attribute(Tree rule, String attrName, @Nullable T def) {
Tree attr = is(rule)? findAttributeValueNode(findChild(rule, ATTRS), attrName) : null;
Object attrVal = getLiteralValue(attr);
if (attrVal != null) return attr == NULL ? def : (T) attrVal;
return def;
}
}
}