package sdsi;

import sdsi.sexp.*;

/**
 * Superclass of the "special-forms" tags.
 *
 * @see TEPrefix
 * @see TERange
 * @see TESet
 * @see TEStar
 * @see TENull
 */
abstract class TESpecial
	extends TESDSIObject {

	// Java's constructor non-inheritance sucks.
	TESpecial() {
		super();
	}
	TESpecial(SexpList l) {
		super(l);
	}

	public static TESpecial parse(SexpList l)
		throws SexpParseException {
		if (l.size() == 1) {
			if ((l.elementAt(0) instanceof SexpString)
				&& ((SexpString) l.elementAt(0)).stringContent().equals("*")) {
				return new TEStar(l);
			} else {
				throw new SexpParseException("Hey, this Sexp isn't special!");
			}
		}

		String starType = ((SexpString)l.elementAt(1)).stringContent();
		if (starType.equals("set")) {
			return new TESet(l);
		} else if (starType.equals("range")) {
			return new TERange(l);
		} else if (starType.equals("prefix")) {
			return new TEPrefix(l);
		} else if (starType.equals("null")) {
			if (l.size()!=2) {
				throw new SexpParseException("Broken null pseudo-tag");
			}
			return TENull.getNull();
		} else {
			throw new SexpParseException("Unknown star type "
				+starType+" in tag");
		}
	}

	/**
	 * The string that appears after the * in this classes' special
	 * form.
	 */
	abstract String mySpecialToken();

	/**
	 * Calls subclass's mySpecialToken() method.
	 * Returns the number of 'arguments' in this object's list
	 * representation, not counting the first two (* token).
	 * Verifies that the first two arguments have the right structure,
	 * as well.
	 * Meant to be used in constructors; assumes super(l) has already
	 * been called.
	 */
	int countArgs()
		throws SexpParseException {
		SexpList l = getSrep();
		if (l.size()<2
			|| !(l.elementAt(0) instanceof SexpString)
			|| !((SexpString) l.elementAt(0)).stringContent().equals("*")
			|| !(l.elementAt(1) instanceof SexpString)
			|| !((SexpString) l.elementAt(1))
				.stringContent().equals(mySpecialToken())) {
			throw new SexpParseException(
				"(* "+mySpecialToken()+" ...) tag not encoded properly.");
		}
		return l.size()-2;
	}

	/**
	 * Like countArgs, but requires the number of (extra) args is n.
	 */
	void requireArgs(int n)
		throws SexpParseException {
		if (countArgs()!=n) {
			throw new SexpParseException(
				"(* "+mySpecialToken()+" ...) tag not encoded properly "
				+"(expected "+n+" arguments)");
		}
	}
}
