package util.gdl;

import java.util.Collection;

import util.gdl.grammar.Gdl;
import util.gdl.grammar.GdlConstant;
import util.gdl.grammar.GdlDistinct;
import util.gdl.grammar.GdlFunction;
import util.gdl.grammar.GdlLiteral;
import util.gdl.grammar.GdlNot;
import util.gdl.grammar.GdlOr;
import util.gdl.grammar.GdlProposition;
import util.gdl.grammar.GdlRelation;
import util.gdl.grammar.GdlRule;
import util.gdl.grammar.GdlSentence;
import util.gdl.grammar.GdlTerm;
import util.gdl.grammar.GdlVariable;

public class GdlVisitors {
	/**
	 * Visits the given Gdl object and any contained Gdl objects within
	 * with the given GdlVisitor. For example, when called on a GdlRule,
	 * the visitor's visitConstant function is called once for every
	 * constant anywhere in the head or body of the rule.
	 * 
	 * @author Alex Landau
	 */
	public static void visitAll(Gdl gdl, GdlVisitor visitor) {
		visitor.visitGdl(gdl);
		if (gdl instanceof GdlTerm) {
			visitTerm((GdlTerm) gdl, visitor);
		} else if (gdl instanceof GdlLiteral) {
			visitLiteral((GdlLiteral) gdl, visitor);
		} else if (gdl instanceof GdlRule) {
			visitRule((GdlRule) gdl, visitor);
		} else {
			throw new RuntimeException("Unexpected Gdl type " + gdl.getClass());
		}
	}
	public static void visitAll(Collection<? extends Gdl> collection, GdlVisitor visitor) {
		for (Gdl gdl : collection) {
			visitAll(gdl, visitor);
		}
	}
	private static void visitRule(GdlRule rule, GdlVisitor visitor) {
		visitor.visitRule(rule);
		visitAll(rule.getHead(), visitor);
		visitAll(rule.getBody(), visitor);
	}
	private static void visitLiteral(GdlLiteral literal, GdlVisitor visitor) {
		visitor.visitLiteral(literal);
		if (literal instanceof GdlSentence) {
			visitSentence((GdlSentence) literal, visitor);
		} else if (literal instanceof GdlNot) {
			visitNot((GdlNot) literal, visitor);
		} else if (literal instanceof GdlOr) {
			visitOr((GdlOr) literal, visitor);
		} else if (literal instanceof GdlDistinct) {
			visitDistinct((GdlDistinct) literal, visitor);
		} else {
			throw new RuntimeException("Unexpected GdlLiteral type " + literal.getClass());
		}
	}
	private static void visitDistinct(GdlDistinct distinct, GdlVisitor visitor) {
		visitor.visitDistinct(distinct);
		visitAll(distinct.getArg1(), visitor);
		visitAll(distinct.getArg2(), visitor);
	}
	private static void visitOr(GdlOr or, GdlVisitor visitor) {
		visitor.visitOr(or);
		for (int i = 0; i < or.arity(); i++) {
			visitAll(or.get(i), visitor);
		}
	}
	private static void visitNot(GdlNot not, GdlVisitor visitor) {
		visitor.visitNot(not);
		visitAll(not.getBody(), visitor);
	}
	private static void visitSentence(GdlSentence sentence, GdlVisitor visitor) {
		visitor.visitSentence(sentence);
		if (sentence instanceof GdlProposition) {
			visitProposition((GdlProposition) sentence, visitor);
		} else if (sentence instanceof GdlRelation) {
			visitRelation((GdlRelation) sentence, visitor);
		} else {
			throw new RuntimeException("Unexpected GdlSentence type " + sentence.getClass());
		}
	}
	private static void visitRelation(GdlRelation relation, GdlVisitor visitor) {
		visitor.visitRelation(relation);
		visitAll(relation.getName(), visitor);
		visitAll(relation.getBody(), visitor);
	}
	private static void visitProposition(GdlProposition proposition,
			GdlVisitor visitor) {
		visitor.visitProposition(proposition);
		visitAll(proposition.getName(), visitor);
	}
	private static void visitTerm(GdlTerm term, GdlVisitor visitor) {
		visitor.visitTerm(term);
		if (term instanceof GdlConstant) {
			visitor.visitConstant((GdlConstant) term);
		} else if (term instanceof GdlVariable) {
			visitor.visitVariable((GdlVariable) term);
		} else if (term instanceof GdlFunction) {
			visitFunction((GdlFunction) term, visitor);
		}
	}
	private static void visitFunction(GdlFunction function, GdlVisitor visitor) {
		visitor.visitFunction(function);
		visitAll(function.getName(), visitor);
		visitAll(function.getBody(), visitor);
	}
}

@@ -3859,32 +3859,122 @@
 erm, visitor);%0D%0A
+%09%09%7D else %7B%0D%0A%09%09%09throw new RuntimeException(%22Unexpected GdlTerm type %22 + term.getClass());%0D%0A
 %09%09%7D%0D%0A%09%7D%0D%0A%09privat

Add an error when a GdlTerm doesn't match any of the known concrete types.