/* ____ ____ ____ ____ ______ *\
** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
** /_____/\____/\___/\____/____/ **
\* */
// $Id$
package meta.scalac.checkers;
import meta.java.Type;
import meta.scalac.ast.AbstractTreeCaseExpander;
import meta.scalac.ast.TreeKind;
import meta.scalac.ast.TreeType;
import meta.scalac.ast.TreeNode;
import meta.scalac.ast.TreeField;
import meta.scalac.ast.TreeFieldLink;
public class MetaCheckTreeNodes extends AbstractTreeCaseExpander {
//########################################################################
// Public Methods
public void printTreeCaseBody(TreeNode node) {
if (node.fields != null) {
for (int i = 0; i < node.fields.length; i++) {
TreeField field = node.fields[i];
printCheckField(node, field.type, field.name, "i");
}
if (node.hasLinkedFields()) {
writer.println("Symbol symbol = tree.symbol();");
writer.print("if (symbol != null)").lbrace();
for (int i = 0; i < node.fields.length; i++)
if (node.fields[i].link != null)
printCheckFieldLink(node.fields[i]);
writer.rbrace();
}
}
printCheckNode(node);
writer.println("return;");
}
private void printCheckNode(TreeNode node) {
if (node.start.constant != null) {
writer.println("assert global.currentPhase.id >= " +
"global.PHASE."+node.start.constant + ".id :").indent();
writer.println("\"cannot create instance of " + node.name +
" before phase " + node.start.name + ", \" +");
writer.println(
"\"current phase is \" + " + "global.currentPhase;").undent();
}
if (node.stop.constant != null) {
writer.println("assert global.currentPhase.id <= " +
"global.PHASE."+node.stop.constant + ".id :").indent();
writer.println("\"cannot create instance of " + node.name +
" after phase " + node.stop.name + ", \" +");
writer.println(
"\"current phase is \" + " + "global.currentPhase;").undent();
}
}
private void printCheckField(TreeNode node,Type type,String name,String i){
if (type.isPrimitive()) return;
writer.println("assert " + name + " != null :").indent();
printNullValue(node, name);
writer.println(";").undent();
switch (type) {
case Reference(_, _):
break;
case Array(Type item):
writer.print(
"for (int "+i+" = 0; "+i+" < "+name+".length; "+i+"++)");
writer.lbrace();
printCheckField(node, item, name+"["+i+"]", i+"i");
writer.rbrace();
break;
case TreeType.Name(TreeKind kind):
if (kind != TreeKind.Any && kind != TreeKind.Test) {
writer.println("assert " + (kind == TreeKind.Type ? "" : "!")+
name +".isTypeName() :").indent();
printWrongKind(node, name, kind);
writer.println(";").undent();
}
break;
case TreeType.Tree(TreeKind kind):
if (kind != TreeKind.Any) {
writer.println("assert " +
name + ".is" + kind + "() :").indent();
printWrongKind(node, name, kind);
writer.println(";").undent();
}
break;
case TreeType.Node(_):
break;
default:
throw new Error(type.getClass().getName());
}
}
private void printCheckFieldLink(TreeField field) {
String getter = field.link.getLink();
writer.println("assert symbol." +getter+ " == " +field+ " :").indent();
writer.println("\"symbol and tree " + field.link + " differ: \"+" +
"symbol." + getter + "+\" != \"+" +field+ ";");
writer.undent();
}
private void printNullValue(TreeNode node, String field) {
String expanded = getExpandedField(field);
writer.print("\"field " +expanded+ " of class " +node+ " is null\"");
}
private void printWrongKind(TreeNode node, String field, TreeKind kind) {
String expanded = getExpandedField(field);
writer.println("\"field " + expanded + " of class " + node +
" is not of kind " + kind + ", \" +");
writer.print("\"found: \" + Debug.show("+field+")");
// !!! " + \" of kind \" + kind("+field+")";
}
private String getExpandedField(String field) {
int begin = field.indexOf('[');
if (begin < 0) return field;
StringBuffer buffer = new StringBuffer(field.substring(0, begin));
for (int end; (end = field.indexOf(']', begin)) >= 0; begin = end + 1){
String index = field.substring(begin + 1, end);
buffer.append("[\"+").append(index).append("+\"]");
}
return buffer.toString();
}
//########################################################################
}
/* !!!
protected static String kind(Tree tree) {
switch (tree) {
case Select(_, Name name): return kind(name);
case Ident(Name name): return kind(name);
}
return "unknown";
}
protected static String kind(Name name) {
if (name.isTypeName()) return "Type";
if (name.isTermName()) return "Term";
if (name.isConstrName()) return "Constr";
return "unknown";
}
*/