public void print(int l)
        {
            print(l, "SchemaText SchemaExpression");
            m_schemaText.print(l + 1);
        }
    }

    public class AstSchemaReferenceS extends AstSchemaExpression
    {
        AstSchemaReference m_schemaReference;

        public void print(int l)
        {
            print(l, "SchemaReference SchemaExpression");
            m_schemaReference.print(l + 1);
        }
    }

    public class AstNotS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpression;

        public void print(int l)
        {
            print(l, "Not SchemaExpression");
            m_schemaExpression.print(l + 1);
        }
    }

    public class AstPreS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpression;

        public void print(int l)
        {
            print(l, "pre SchemaExpression");
            m_schemaExpression.print(l + 1);
        }
    }

    public class AstAndS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpressionL;
        AstSchemaExpression m_schemaExpressionR;

        public void print(int l)
        {
            print(l, "AND SchemaExpression");
            m_schemaExpressionL.print(l + 1);
            m_schemaExpressionR.print(l + 1);
        }
    }

    public class AstOrS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpressionL;
        AstSchemaExpression m_schemaExpressionR;

        public void print(int l)
        {
            print(l, "OR SchemaExpression");
            m_schemaExpressionL.print(l + 1);
            m_schemaExpressionR.print(l + 1);
        }
    }

    public class AstImpliesS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpressionL;
        AstSchemaExpression m_schemaExpressionR;

        public void print(int l)
        {
            print(l, "IMPLIES SchemaExpression");
            m_schemaExpressionL.print(l + 1);
            m_schemaExpressionR.print(l + 1);
        }
    }

    public class AstBiimpliesS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpressionL;
        AstSchemaExpression m_schemaExpressionR;

        public void print(int l)
        {
            print(l, "BIIMPLIES SchemaExpression");
            m_schemaExpressionL.print(l + 1);
            m_schemaExpressionR.print(l + 1);
        }
    }

    public class AstProjS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpressionL;
        AstSchemaExpression m_schemaExpressionR;

        public void print(int l)
        {
            print(l, "PROJ SchemaExpression");
            m_schemaExpressionL.print(l + 1);
            m_schemaExpressionR.print(l + 1);
        }
    }

    public class AstBslashS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpression;
        AstDeclarationNameList m_declarationNameList;

        public void print(int l)
        {
            print(l, "BSLASH SchemaExpression");
            m_schemaExpression.print(l + 1);
            m_declarationNameList.print(l + 1);
        }
    }

    public class AstCompS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpressionL;
        AstSchemaExpression m_schemaExpressionR;

        public void print(int l)
        {
            print(l, "COMP SchemaExpression");
            m_schemaExpressionL.print(l + 1);
            m_schemaExpressionR.print(l + 1);
        }
    }

    public class AstMgtS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpressionL;
        AstSchemaExpression m_schemaExpressionR;

        public void print(int l)
        {
            print(l, ">> SchemaExpression");
            m_schemaExpressionL.print(l + 1);
            m_schemaExpressionR.print(l + 1);
        }
    }

    public class AstParenS extends AstSchemaExpression
    {
        AstSchemaExpression m_schemaExpression;

        public void print(int l)
        {
            print(l, "() SchemaExpression");
            m_schemaExpression.print(l + 1);
        }
    }

    /*
     * Expression
     */
    public class AstExpression extends AstBase
    {
        SpecObject specObject;
        String property;

        public AstExpression(SpecObject specObject, String property)
        {
            this.specObject = specObject;
            this.property = property;
        }

        public void checkType()
        {
            getType();
        }
    }

    public class AstBinaryOpX extends AstExpression
    {
        AstExpression m_expressionL;
        AstExpression m_expressionR;

        public AstBinaryOpX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            m_expressionL.print(l);
            m_expressionR.print(l);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expressionL.populateTypeTable(m_stable);
            m_expressionR.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_expressionL.populateSymbolTable();
            m_expressionR.populateSymbolTable();
        }

        public AstType getType()
        {
            AstType typeL = m_expressionL.getType();
            AstType typeR = m_expressionR.getType();
            if ((typeL.isUndefined())
                    || (typeR.isUndefined()))
                {
                return new AstType();
                }
            if (!typeL.isCompatible(typeR))
                {
                reportTypeError("Type mismatch",
                                m_token,
                                specObject,
                                property
                );
                }
            return typeL.resultantType(typeR);
        }
    }

    public class AstIfThenElseX extends AstExpression
    {
        AstPredicate m_predicate;
        AstExpression m_then;
        AstExpression m_else;

        public AstIfThenElseX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "IfThenElse");
            m_predicate.print(l + 1);
            m_then.print(l + 1);
            m_else.print(l + 1);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_predicate.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_predicate.populateSymbolTable();
            m_then.populateSymbolTable();
            m_else.populateSymbolTable();
        }

        public AstType getType()
        {
            AstType t1 = m_then.getType();
            AstType t2 = m_else.getType();
            if ((t1.isUndefined())
                    || (t2.isUndefined()))
                {
                return new AstType();
                }
            if (!t1.isCompatible(t2))
                {
                reportTypeError(
                        "The expression used for the then clause is a different type than the one used for the else clause",
                        m_then.m_token,
                        specObject,
                        property
                );
                }
            return t1.resultantType(t2);
        }
    }

    public class AstCrossProductX extends AstBinaryOpX
    {
        public AstCrossProductX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "CrossProduct");
            super.print(l + 1);
        }

        public AstType getType()
        {
            AstType typeL = m_expressionL.getType();
            AstType typeR = m_expressionR.getType();
            if ((typeL.isUndefined())
                    || (typeR.isUndefined()))
                {
                return new AstType();
                }
            typeL = typeL.getSetType();
            typeR = typeR.getSetType();
            if ((typeL == null) || (typeR == null))
                {
                reportTypeError("Both expressions of a cross-product must evaluate to a set",
                                m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            AstType result = new AstType(AstType.TYPE_SET);
            result.m_setType = new AstType(AstType.TYPE_TUPLE);
            result.m_setType.newTuple(typeL, typeR);
            return result;
        }
    }

    public class AstInfixGenericNameX extends AstBinaryOpX
    {
        AstInfixGenericName m_infixGenericName = new AstInfixGenericName();

        public AstInfixGenericNameX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            m_infixGenericName.print(l);
            super.print(l + 1);
        }

        public String getName()
        {
            return m_infixGenericName.getName();
        }

        public AstType getType()
        {
            AstType typeL = m_expressionL.getType();
            AstType typeR = m_expressionR.getType();
            if ((typeL.isUndefined())
                    || (typeR.isUndefined()))
                {
                return new AstType();
                }
            if ((!typeL.isSet() || !typeR.isSet()))
                {
                reportTypeError("Both sides of an infix generic operator must be sets",
                                m_infixGenericName.m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            AstType type = new AstType(AstType.TYPE_SET);
            type.m_setType = new AstType(AstType.TYPE_SET);
            type.m_setType.m_setType = new AstType(AstType.TYPE_TUPLE);
            type.m_setType.m_setType.newTuple(typeL.getSetType(), typeR.getSetType());
            return type;
        }
    }

    public class AstInfixFunctionNameX extends AstBinaryOpX
    {
        AstInfixFunctionName m_infixFunctionName = new AstInfixFunctionName();

        public AstInfixFunctionNameX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            m_infixFunctionName.print(l);
            super.print(l + 1);
        }

        public AstType getType()
        {
            boolean bad = false;

            int tid = m_infixFunctionName.m_token.m_id;
            String tname = m_infixFunctionName.m_token.m_value;

            AstType typeL = m_expressionL.getType();
            AstType typeR = m_expressionR.getType();

            if ((typeL.isUndefined())
                    || (typeR.isUndefined()))
                {
                return new AstType();
                }

            if (tid == TozeTokenizer.TOKEN_MAP)
                {
                AstType type = new AstType(AstType.TYPE_TUPLE);
                type.m_tupleTypes.add(typeL);
                type.m_tupleTypes.add(typeR);
                return type;
                }
            if ((tid == TozeTokenizer.TOKEN_PLUS)
                    || (tid == TozeTokenizer.TOKEN_MINUS)
                    || (tid == TozeTokenizer.TOKEN_DIV)
                    || (tid == TozeTokenizer.TOKEN_MOD)
                    || (tid == TozeTokenizer.TOKEN_FSLASH)
                    || (tid == TozeTokenizer.TOKEN_TIMES))
                {
                AstType rtype = typeL.resultantType(typeR);
                if (!rtype.isANumber())
                    {
                    reportTypeError("The expressions for the " + tname + " operator must be numbers",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return rtype;
                }

            if ((tid == TozeTokenizer.TOKEN_UNI)
                    || (tid == TozeTokenizer.TOKEN_SETMINUS)
                    || (tid == TozeTokenizer.TOKEN_INT)
                    || (tid == TozeTokenizer.TOKEN_BSLASH))
                {
                if (!typeL.isSet() || !typeR.isSet())
                    {
                    reportTypeError("Expressions for the " + tname + " operator must be sets",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                if (!typeL.isEqual(typeR))
                    {
                    reportTypeError("Sets must be the same type for the operator " + tname,
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return typeL;
                }

            if ((tid == TozeTokenizer.TOKEN_CAT)
                    || (tid == TozeTokenizer.TOKEN_DCAT)
                    || (tid == TozeTokenizer.TOKEN_PREFIX)
                    || (tid == TozeTokenizer.TOKEN_SUFFIX))
                {
                if (!typeL.isSequence() || !typeR.isSequence())
                    {
                    reportTypeError("Expressions for the " + tname + " operator must be sequences",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return typeL;
                }

            if (tid == TozeTokenizer.TOKEN_UPTO)
                {
                if (!typeL.isANumber()
                        || !typeR.isANumber())
                    {
                    reportTypeError("Expressions for " + tname + " must be numbers",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                AstType type = new AstType(AstType.TYPE_SET);
                type.m_setType = typeL;
                return type;
                }

            if ((tid == TozeTokenizer.TOKEN_FOVR)
                    || (tid == TozeTokenizer.TOKEN_FCMP)
                    || (tid == TozeTokenizer.TOKEN_CIRC))
                {
                if (!typeL.isRelation()
                        || !typeR.isRelation())
                    {
                    reportTypeError("Expressions for " + tname + " must be relations",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                if (!typeL.isEqual(typeR))
                    {
                    reportTypeError("Relations used in " + tname + " must be of the same type",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return typeL;
                }

            if ((tid == TozeTokenizer.TOKEN_DRES)
                    || (tid == TozeTokenizer.TOKEN_DSUB))
                {
                if (!typeL.isSet())
                    {
                    reportTypeError("Left-hand argument to " + tname + " must be a set",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    bad = true;
                    }
                if (!typeR.isRelation())
                    {
                    reportTypeError("Right-hand argument to " + tname + " must be a relation",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    bad = true;
                    }
                if (bad)
                    {
                    return new AstType();
                    }
                if (!((AstType) typeR.getSetType().m_tupleTypes.get(0)).isEqual(typeL.getSetType()))
                    {
                    reportTypeError("Type of set must be the same as the domain type of the range",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return typeR;
                }

            if ((tid == TozeTokenizer.TOKEN_RRES)
                    || (tid == TozeTokenizer.TOKEN_RSUB))
                {
                if (!typeR.isSet())
                    {
                    reportTypeError("Right-hand argument to " + tname + " must be a set",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    bad = true;
                    }
                if (!typeL.isRelation())
                    {
                    reportTypeError("Left-hand argument to " + tname + " must be a relation",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    bad = true;
                    }
                if (bad)
                    {
                    return new AstType();
                    }
                if (!((AstType) typeL.getSetType().m_tupleTypes.get(1)).isEqual(typeR.getSetType()))
                    {
                    reportTypeError("Type of set must be the same as the range type of the relation",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return typeL;
                }

            if ((tid == TozeTokenizer.TOKEN_PROJECT))
                {
                if (!typeL.isSequence())
                    {
                    reportTypeError("Left-hand expression for a projection must be a sequence",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    bad = true;
                    }
                if (!typeR.isSet())
                    {
                    reportTypeError("Right-hand expression for a projection must be a set",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    bad = true;
                    }
                if (bad)
                    {
                    return new AstType();
                    }
                AstType tl = (AstType) typeL.getSetType().m_tupleTypes.get(1);
                AstType tr = typeR.getSetType();
                if (!tl.isCompatible(tr))
                    {
                    reportTypeError("Type of set must be the same as the sequence type.",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    }
                return typeL;
                }

            if ((tid == TozeTokenizer.TOKEN_EXTRACT))
                {
                if (!typeL.isSet())
                    {
                    reportTypeError("Left-hand expression must be a set",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    bad = true;
                    }
                else
                    {
                    }
                if (!typeR.isSequence())
                    {
                    reportTypeError("Right-hand expression for a projection must be a sequence",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    bad = true;
                    }
                if (bad)
                    {
                    return new AstType();
                    }
                AstType tl = typeL.getSetType();
            /*
             * Check that the set contains natural numbers.
             */
                if (!tl.isANumber())
                    {
                    reportTypeError("The set must contain numbers",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    }
                return typeR;
                }

            if (tid == TozeTokenizer.TOKEN_HASH)
                {
                if (!typeL.isBag())
                    {
                    reportTypeError("Left-hand expression for '#' must be a bag",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                if (!((AstType) typeL.getSetType().m_tupleTypes.get(0)).isEqual(typeR))
                    {
                    reportTypeError("Right-hand expression for '#' must be the same type as contained in the bag",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return new AstType(AstType.TYPE_NATURAL);
                }

            if (tid == TozeTokenizer.TOKEN_UPLUS)
                {
                if (!typeL.isBag()
                        || !typeR.isBag())
                    {
                    reportTypeError("Expressions for bag union must be bags",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }

                if (!typeL.isEqual(typeR))
                    {
                    reportTypeError("Both sides of bag union must be the same type",
                                    m_infixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    }
                }

            return new AstType();
        }
    }

    public class AstPowerX extends AstExpression
    {
        AstExpression m_expression;

        public AstPowerX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expression.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_expression.populateSymbolTable();
        }

        public AstType getType()
        {
            AstType ttype = m_expression.getType();
            if (ttype.isUndefined())
                {
                return new AstType();
                }
            if (ttype.getSetType() == null)
                {
                reportTypeError("Power set must be applied to a set",
                                m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            AstType type = new AstType(AstType.TYPE_SET);
            type.m_setType = ttype;
            return type;
        }
    }

    public class AstUnaryOpX extends AstExpression
    {
        AstExpression m_expression;

        public AstUnaryOpX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, m_token.m_value);
            m_expression.print(l + 1);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expression.populateTypeTable(stable);
        }

        public void populateSymbolTable()
        {
            m_expression.populateSymbolTable();
        }

        public AstType getType()
        {
            return m_expression.getType();
        }
    }

    public class AstPrefixGenericNameX extends AstUnaryOpX
    {
        AstPrefixGenericName m_prefixGenericName = new AstPrefixGenericName();

        public AstPrefixGenericNameX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            m_prefixGenericName.print(l);
        }

        public AstType getType()
        {
            switch (m_prefixGenericName.m_token.m_id)
                {
                case TozeTokenizer.TOKEN_SEQ:
                case TozeTokenizer.TOKEN_SEQONE:
                case TozeTokenizer.TOKEN_ISEQ:
                    AstType t = m_expression.getType();
                    if (t.isUndefined())
                        {
                        return new AstType();
                        }
//               AstType type = new AstType(AstType.TYPE_SET);
//               type.m_setType = new AstType(AstType.TYPE_SEQUENCE);
                    if (t.isSet())
                        {
                        t = t.getSetType();
                        }
                    AstType rtype = new AstType(AstType.TYPE_SET);
                    rtype.m_setType = new AstType(AstType.TYPE_SEQUENCE);
                    rtype.m_setType.m_setType = new AstType(AstType.TYPE_TUPLE);
                    rtype.m_setType.m_setType.newTuple(new AstType(AstType.TYPE_NATURAL1),
                                                       t
                    );
                    rtype.m_setType.m_setType.m_tupleIsSeq = true;
                    return rtype;
                case TozeTokenizer.TOKEN_BAG:
                    t = m_expression.getType();
                    if (t.isUndefined())
                        {
                        return new AstType();
                        }
//               type = new AstType(AstType.TYPE_SET);
//               type.m_setType = new AstType(AstType.TYPE_BAG);
                    if (t.isSet())
                        {
                        t = t.getSetType();
                        }
                    rtype = new AstType(AstType.TYPE_SET);
                    rtype.m_setType = new AstType(AstType.TYPE_BAG);
                    rtype.m_setType.m_setType = new AstType(AstType.TYPE_TUPLE);
                    rtype.m_setType.m_setType.newTuple(t,
                                                       new AstType(AstType.TYPE_NATURAL1)
                    );
                    rtype.m_setType.m_setType.m_tupleIsSeq = true;
                    return rtype;
                }
            return new AstType();
        }
    }

    public class AstHyphenX extends AstUnaryOpX
    {
        AstDecorations m_decoration;

        public AstHyphenX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expression.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_expression.populateSymbolTable();
        }

        public AstType getType()
        {
            AstType t = m_expression.getType();
            if (!t.isANumber())
                {
                reportTypeError("The expression for - must be a number",
                                m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            return t;
        }
    }

    public class AstImageX extends AstExpression // (| |)
    {
        AstExpression m_expression1;
        AstExpression m_expression0;
        AstDecorations m_decoration;

        public AstImageX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expression1.populateTypeTable(m_stable);
            m_expression0.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_expression1.populateSymbolTable();
            m_expression0.populateSymbolTable();
        }

        public AstType getType()
        {
            boolean bad = false;
            AstType typeL = m_expression1.getType();
            AstType typeM = m_expression0.getType();

            if ((typeL.isUndefined())
                    || (typeM.isUndefined()))
                {
                return new AstType();
                }

            if (!typeL.isRelation())
                {
                reportTypeError("Left-hand expression to the image operator must be a relation",
                                m_token,
                                specObject,
                                property
                );
                bad = true;
                }
            if (!typeM.isSet())
                {
                reportTypeError("Inside expression of the image operator must be a set",
                                m_token,
                                specObject,
                                property
                );
                bad = true;
                }
            if (bad)
                {
                return new AstType();
                }
            if (!typeM.getSetType().isEqual((AstType) typeL.getSetType().m_tupleTypes.get(0)))
                {
                reportTypeError(
                        "The type of the inside set expression must the the same type as the domain type of the relation for the image operator",
                        m_token,
                        specObject,
                        property
                );
                return new AstType();
                }
            AstType type = new AstType(AstType.TYPE_SET);
            type.m_setType = (AstType) typeL.getSetType().m_tupleTypes.get(1);
            return type;
        }
    }

    public class AstExpressionListX extends AstExpression
    {
        List m_expressions = new ArrayList();

        public AstExpressionListX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstBase) m_expressions.get(i)).populateTypeTable(m_stable);
                }
        }

        public void populateSymbolTable()
        {
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstBase) m_expressions.get(i)).populateSymbolTable();
                }
        }

        public AstType getType()
        {
            AstType type = new AstType(AstType.TYPE_TUPLE);
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                AstType t = ((AstBase) m_expressions.get(i)).getType();
                type.m_tupleTypes.add(t);
                }

            /*
             * Special case where a tuple is surrounded by parenthesis
             */

            if (m_expressions.size() == 1)
                {
                AstType t = (AstType) type.m_tupleTypes.get(0);
                if (t.getType() == AstType.TYPE_TUPLE)
                    {
                    return t;
                    }
                }

            return type;
        }
    }

    public class AstDistUnionX extends AstExpression
    {
        AstExpression m_expression = null;

        public AstDistUnionX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expression.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_expression.populateSymbolTable();
        }

        public AstType getType()
        {
            AstType type = m_expression.getType();
            if (type.isUndefined())
                {
                return new AstType();
                }
            if (type.getType() != AstType.TYPE_SET)
                {
                reportTypeError("Expression used in distributed union must be a set of sets.",
                                m_token,
                                specObject,
                                property
                );
                return new AstType();
                }

            /*
             * If the set is a tuple, then we need to make sure that each tuple
             * is of the same type.
             */

            if (type.getSetType().getType() == AstType.TYPE_TUPLE)
                {
                int i;
                AstType stype = type.getSetType();
                if (stype.m_tupleTypes.size() == 0)
                    {
                    return new AstType(AstType.TYPE_EMPTY);
                    }
                AstType type1 = (AstType) stype.m_tupleTypes.get(0);
                for (i = 1; i < stype.m_tupleTypes.size(); i++)
                    {
                    AstType type2 = (AstType) stype.m_tupleTypes.get(i);
                    if (!type1.isCompatible(type2))
                        {
                        reportTypeError("All sets used in a distributed union must be of the same type.",
                                        m_token,
                                        specObject,
                                        property
                        );
                        return new AstType();
                        }
                    }
                return type1;
                }
            else
                {
                if (type.getSetType().getType() != AstType.TYPE_SET)
                    {
                    reportTypeError("Expression used in distributed union must be a set of sets.",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }

                return type.getSetType();
                }
        }
    }

    public class AstDistIntersectionX extends AstExpression
    {
        AstExpression m_expression = null;

        public AstDistIntersectionX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expression.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_expression.populateSymbolTable();
        }

        public AstType getType()
        {
            AstType type = m_expression.getType();
            if (type.isUndefined())
                {
                return new AstType();
                }
            if (type.getType() != AstType.TYPE_SET)
                {
                reportTypeError("Expression used in distributed intersection must be a set of sets.",
                                m_token,
                                specObject,
                                property
                );
                return new AstType();
                }

            /*
             * If the set is a tuple, then we need to make sure that each tuple
             * is of the same type.
             */

            if (type.getSetType().getType() == AstType.TYPE_TUPLE)
                {
                int i;
                AstType stype = type.getSetType();
                if (stype.m_tupleTypes.size() == 0)
                    {
                    return new AstType(AstType.TYPE_EMPTY);
                    }
                AstType type1 = (AstType) stype.m_tupleTypes.get(0);
                for (i = 1; i < stype.m_tupleTypes.size(); i++)
                    {
                    AstType type2 = (AstType) stype.m_tupleTypes.get(i);
                    if (!type1.isCompatible(type2))
                        {
                        reportTypeError("All sets used in a distributed intersection must be of the same type.",
                                        m_token,
                                        specObject,
                                        property
                        );
                        return new AstType();
                        }
                    }
                return type1;
                }
            else
                {
                if (type.getSetType().getType() != AstType.TYPE_SET)
                    {
                    reportTypeError("Expression used in distributed intersection must be a set of sets.",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }

                return type.getSetType();
                }
        }
    }

    public class AstVariableX extends AstExpression
    {
        AstVariableName m_variable;
        AstActualParameters m_actualParameters;

        public AstVariableX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstSelfX extends AstExpression
    {
        public AstSelfX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstNumberX extends AstExpression
    {
        public AstNumberX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, m_token.m_value);
        }

        public AstType getType()
        {
            AstType type = new AstType();
            if (m_token.m_value.indexOf('.') >= 0)
                {
                type.m_type = AstType.TYPE_REAL;
                }
            else
                {
                type.m_type = AstType.TYPE_NATURAL;
                }
            return type;
        }
    }

    public class AstSchemaReferenceX extends AstExpression
    {
        AstSchemaReference m_schemaReference;

        public AstSchemaReferenceX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstClassNameX extends AstExpression
    {
        AstClassName m_className;
        AstActualParameters m_actualParameters;
        AstRenameList m_renameList;

        public AstClassNameX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstDownArrowX extends AstExpression
    {
        AstExpression m_expression;

        public AstDownArrowX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expression.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_expression.populateSymbolTable();
        }

        public AstType getType()
        {
            if (m_expression == null)
                {
                return new AstType();
                }
            return m_expression.getType();
        }
    }

    public class AstUnionX extends AstBinaryOpX
    {
        public void print(int l)
        {
            print(l, "Union");
            super.print(l + 1);
        }

        public AstUnionX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public AstType getType()
        {
            AstType typeL = m_expressionL.getType();
            AstType typeR = m_expressionR.getType();

            if ((typeL.isUndefined())
                    || (typeR.isUndefined()))
                {
                return new AstType();
                }

            if (!typeL.isSet() || !typeR.isSet())
                {
                reportTypeError(
                        "Expressions for the " + Character.toString(TozeFontMap.CHAR_CUP) + " operator must be sets",
                        m_token,
                        specObject,
                        property
                );
                return new AstType();
                }
            if (!typeL.isEqual(typeR))
                {
                reportTypeError(
                        "Sets must be the same type for the operator " + Character.toString(TozeFontMap.CHAR_CUP),
                        m_token,
                        specObject,
                        property
                );
                return new AstType();
                }
            return typeL;
        }
    }

    public class AstCopyrightX extends AstUnaryOpX
    {
        public AstCopyrightX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstAngleX extends AstExpression
    {
        List m_expressions = new ArrayList();

        public AstAngleX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstBagX extends AstExpression
    {
        List m_expressions = new ArrayList();

        public AstBagX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            int i;
            print(l, "BagExpression");
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstExpression) m_expressions.get(i)).print(l + 1);
                }
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstBase) m_expressions.get(i)).populateTypeTable(m_stable);
                }
        }

        public void populateSymbolTable()
        {
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstBase) m_expressions.get(i)).populateSymbolTable();
                }
        }

        public AstType getType()
        {
            int i;
            boolean wasUndefined = false;
            AstType type = new AstType(AstType.TYPE_BAG);
            if (m_expressions.size() == 0)
                {
                return new AstType(AstType.TYPE_EMPTY);
                }

            AstType stype = ((AstBase) m_expressions.get(0)).getType();
            if (stype.isUndefined())
                {
                return new AstType();
                }

            for (i = 1; i < m_expressions.size(); i++)
                {
                AstType ttype = ((AstBase) m_expressions.get(i)).getType();
                if (ttype.isUndefined())
                    {
                    wasUndefined = true;
                    }
                else
                    {
                    if (!ttype.isEqual(stype))
                        {
                        reportTypeError("All expressions of a bag must be of the same type",
                                        m_token,
                                        specObject,
                                        property
                        );
                        }
                    }
                }

            if (wasUndefined)
                {
                return new AstType();
                }

            AstType rtype = new AstType(AstType.TYPE_BAG);
            rtype.m_setType = new AstType(AstType.TYPE_TUPLE);
            rtype.m_setType.newTuple(stype,
                                     new AstType(AstType.TYPE_NATURAL1)
            );
            rtype.m_setType.m_tupleIsSeq = false;
            return rtype;
        }
    }

    public class AstThetaX extends AstExpression
    {
        AstSchemaName m_schemaName;
        AstDecorations m_decorations;
        AstRenameList m_renameList;

        public AstThetaX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstMemberX extends AstExpression
    {
        AstExpression m_expression;
        AstVariableName m_variableName;

        public AstMemberX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "AstMember");
            m_expression.print(l + 1);
            m_variableName.print(l + 1);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_expression.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_expression.populateSymbolTable();
        }

        public AstType getType()
        {
            AstType ctype = m_expression.getType();
            if (ctype.isUndefined())
                {
                return new AstType();
                }
            if (ctype == null)
                {
                reportTypeError("Undefined class variable",
                                m_expression.m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            if (ctype.getType() != AstType.TYPE_CLASS)
                {
                reportTypeError("Member access must be from a class type",
                                m_expression.m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            AstType type = null;

            if (m_variableName != null)
                {
                type = ctype.getClassMembers().getTypeVisible(m_variableName.getName());
                }

            if (type == null)
                {
                // the variable name may be null after a class.member syntax
                // where member is blank, handle as a null and use a unique
                // TozeToken
                String member = "<null>";
                TozeToken token = null;

                if (m_variableName != null)
                    {
                    member = m_variableName.getName();
                    token = m_variableName.m_token;
                    }

                if (token == null)
                    {
                    token = new TozeToken(-1, member, -1, -1);
                    }

                reportTypeError("The member " + member + " is not visible",
                                token,
                                specObject,
                                property
                );
                return new AstType();
                }
            if (type.isUndefined())
                {
                reportTypeError("The member " + m_variableName.getName() + " is undefined",
                                m_variableName.m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            return type;
        }
    }

    public class AstPostfixFunctionNameX extends AstUnaryOpX
    {
        AstPostfixFunctionName m_postfixFunctionName;

        public AstPostfixFunctionNameX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public AstType getType()
        {
            AstType type = m_expression.getType();

            if (type.isUndefined())
                {
                return new AstType();
                }

            if ((m_postfixFunctionName.m_token.m_id == TozeTokenizer.TOKEN_TILDE)
                    || (m_postfixFunctionName.m_token.m_id == TozeTokenizer.TOKEN_INV))
                {
                if (!type.isRelation())
                    {
                    reportTypeError("The argument to '~' must be a relation",
                                    m_postfixFunctionName.m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }

                AstType rtype = new AstType(AstType.TYPE_SET);
                rtype.m_setType = new AstType(AstType.TYPE_TUPLE);
                rtype.m_setType.newTuple((AstType) type.m_setType.m_tupleTypes.get(1),
                                         (AstType) type.m_setType.m_tupleTypes.get(0)
                );
                return rtype;
                }
            if ((m_postfixFunctionName.m_token.m_id == TozeTokenizer.TOKEN_TCL)
                    || (m_postfixFunctionName.m_token.m_id == TozeTokenizer.TOKEN_RTCL))
                {
                if (!type.isRelation())
                    {
                    reportTypeError(
                            "The argument to '" + m_postfixFunctionName.m_token.m_value + "' must be a relation",
                            m_postfixFunctionName.m_token,
                            specObject,
                            property
                    );
                    return new AstType();
                    }
                }
            return type;
        }
    }

    public class AstParenX extends AstExpression
    {
        public AstParenX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "Parenthesis");
            super.print(l + 1);
        }
    }

    public class AstLambdaX extends AstExpression
    {
        AstSchemaText m_schemaText;
        AstExpression m_expression;

        public AstLambdaX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "Lambda");
            m_schemaText.print(l + 1);
            m_expression.print(l + 1);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_schemaText.populateTypeTable(m_stable);
            m_expression.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_schemaText.populateSymbolTable();
            m_expression.populateSymbolTable();
        }

        public AstType getType()
        {
            m_schemaText.checkType();
            List decls = m_schemaText.m_declaration.m_decls;
            AstType ttype = new AstType(AstType.TYPE_TUPLE);
            int i;
            for (i = 0; i < decls.size(); i++)
                {
                if (decls.get(i) instanceof AstBasicDeclaration1)
                    {
                    AstBasicDeclaration1 dec = (AstBasicDeclaration1) decls.get(i);
                    List names = dec.m_declarationNameList.m_declarationNameList;
                    int j;
                    for (j = 0; j < names.size(); j++)
                        {
                        AstDeclarationName name = (AstDeclarationName) names.get(j);
                        AstType nt = m_stable.getType(name.getName());
                        ttype.m_tupleTypes.add(nt);
                        }
                    }
                }
            AstType et = m_expression.getType();
            if (et.isUndefined())
                {
                return new AstType();
                }
            ttype.m_tupleTypes.add(et);
            AstType type = new AstType(AstType.TYPE_SET);
            type.m_setType = ttype;
            return type;
        }
    }

    public class AstMuX extends AstExpression
    {
        AstSchemaText m_schemaText;
        AstExpression m_expression;

        public AstMuX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstLetX extends AstExpression
    {
        List m_letDefinitions = new ArrayList();
        AstExpression m_expression;

        public AstLetX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    /*
     * This class is a merging of a variable (V), Schema Reference (S), and
     * class (C).
     * This is done because sometimes it is not possible to know at the time of
     * parsing whether something is either of the three.
     *
     * Word -> VSC
     * Word, Decoration -> VS
     * Word, ActualParameters -> VSC
     * Word, RenameList -> SC
     * Word, ActualParameters, RenameList -> SC
     * Word, Decoration, ActualParameters -> VS
     * Word, Decoration, RenameList -> S
     * Word, Decoration, ActualParameters, RenameList -> S
     */
    public class AstVSCX extends AstExpression
    {
        // The Word will be stored in the token in the base class.
        AstDecorations m_decorations;
        AstActualParameters m_actualParameters;
        AstRenameList m_renameList;

        public AstVSCX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "VSC");
            print(l + 1, m_token.m_value);
            if (m_decorations != null)
                {
                m_decorations.print(l + 1);
                }
            if (m_actualParameters != null)
                {
                m_actualParameters.print(l + 1);
                }
            if (m_renameList != null)
                {
                m_renameList.print(l + 1);
                }
        }

        public AstType getType()
        {
            AstType type = m_stable.getTypeDef(getName());
            if (type == null)
                {
                type = m_stable.getType(getName());
                if (type == null)
                    {
                    reportTypeError(getName() + " is undefined",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                if (type.isUndefined())
                    {
                    reportTypeError(getName() + " is undefined",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                }
            return type;
        }

        public String getName()
        {
            if (m_decorations == null)
                {
                return m_token.m_value;
                }
            return m_token.m_value + m_decorations.getName();
        }
    }

    public class AstSetExpressionX extends AstExpression
    {
        public AstSetExpressionX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }
    }

    public class AstSetExpressionX1 extends AstSetExpressionX
    {
        List m_expressions = new ArrayList();

        public AstSetExpressionX1(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            int i;
            print(l, "SetExpression");
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstExpression) m_expressions.get(i)).print(l + 1);
                }
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstBase) m_expressions.get(i)).populateTypeTable(m_stable);
                }
        }

        public void populateSymbolTable()
        {
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstBase) m_expressions.get(i)).populateSymbolTable();
                }
        }

        public AstType getType()
        {
            AstType type;
            int i;
            boolean wasUndefined = false;
//ttp
/*
             * if (m_expressions.size() > 1)
             * {
             * AstType ttype = new AstType();
             * ttype.m_type = AstType.TYPE_TUPLE;
             * for (i=0; i<m_expressions.size(); i++)
             * {
             * type = ((AstBase)m_expressions.get(i)).getType();
             * ttype.m_tupleTypes.add(type);
             * if (type.isUndefined()) wasUndefined = true;
             * }
             * if (wasUndefined) return new AstType();
             * type = new AstType(AstType.TYPE_SET);
             * type.m_setType = ttype;
             * }
             * else if (m_expressions.size() == 1)
             */
            if (m_expressions.size() != 0)
                {
                type = new AstType(AstType.TYPE_SET);
                type.m_setType = ((AstBase) m_expressions.get(0)).getType();
                if (type.m_setType.isUndefined())
                    {
                    return new AstType();
                    }
                }
            else
                {
                type = new AstType(AstType.TYPE_SET);
                type.m_setType = new AstType(AstType.TYPE_EMPTY);
                if (type.m_setType.isUndefined())
                    {
                    return new AstType();
                    }
                }
            return type;
        }
    }

    public class AstSetExpressionX2 extends AstSetExpressionX
    {
        AstSchemaText m_schemaText;
        AstExpression m_expression;

        public AstSetExpressionX2(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "SetExpression");
            if (m_schemaText != null)
                {
                m_schemaText.print(l + 1);
                }
            m_expression.print(l + 1);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = new AstSymbolTable(stable);
            stable.addKid(m_stable);
            if (m_schemaText != null)
                {
                m_schemaText.populateTypeTable(m_stable);
                }
            if (m_expression != null)
                {
                m_expression.populateTypeTable(m_stable);
                }
        }

        public void populateSymbolTable()
        {
            if (m_schemaText != null)
                {
                m_schemaText.populateSymbolTable();
                }
            if (m_expression != null)
                {
                m_expression.populateSymbolTable();
                }
        }

        public AstType getType()
        {
            if (m_schemaText != null)
                {
                m_schemaText.checkType();
                }
            if (m_expression == null)
                {
                return m_schemaText.getType();
                }
            AstType type = new AstType(AstType.TYPE_SET);
            type.m_setType = m_expression.getType();
            if (type.m_setType.isUndefined())
                {
                return new AstType();
                }
            return type;
        }
    }

    public class AstSetExpressionX3 extends AstSetExpressionX
    {
        public AstSetExpressionX3(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "SetExpression - " + m_token.m_value);
        }

        public AstType getType()
        {
            AstType type = new AstType();
            if (m_token.m_id == TozeTokenizer.TOKEN_NAT)
                {
                return m_stable.getTypeDef(m_token.m_value);
                }
            else if (m_token.m_id == TozeTokenizer.TOKEN_NATONE)
                {
                return m_stable.getTypeDef(m_token.m_value);
                }
            else if (m_token.m_id == TozeTokenizer.TOKEN_INTEGER)
                {
                return m_stable.getTypeDef(m_token.m_value);
                }
            else if (m_token.m_id == TozeTokenizer.TOKEN_REAL)
                {
                return m_stable.getTypeDef(m_token.m_value);
                }
            else if (m_token.m_id == TozeTokenizer.TOKEN_BOOL)
                {
                return m_stable.getTypeDef(m_token.m_value);
                }
            return m_stable.getTypeDef(m_token.m_value);
        }
    }

    public class AstSequenceX extends AstExpression
    {
        List m_expressions = new ArrayList();

        public AstSequenceX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void print(int l)
        {
            print(l, "Sequence");
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstBase) m_expressions.get(i)).populateTypeTable(m_stable);
                }
        }

        public void populateSymbolTable()
        {
            int i;
            for (i = 0; i < m_expressions.size(); i++)
                {
                ((AstBase) m_expressions.get(i)).populateSymbolTable();
                }
        }

        public AstType getType()
        {
            int i;
            boolean wasUndefined = false;
            AstType type = new AstType(AstType.TYPE_SEQUENCE);
            if (m_expressions.size() == 0)
                {
                type.m_setType = new AstType(AstType.TYPE_EMPTY);
                return type;
                }

            AstType stype = ((AstBase) m_expressions.get(0)).getType();
            if (stype.isUndefined())
                {
                return new AstType();
                }

            for (i = 1; i < m_expressions.size(); i++)
                {
                AstType ttype = ((AstBase) m_expressions.get(i)).getType();
                if (ttype.isUndefined())
                    {
                    wasUndefined = true;
                    }
                else
                    {
                    if (!ttype.isEqual(stype))
                        {
                        reportTypeError("All expressions of a sequence must be of the same type",
                                        m_token,
                                        specObject,
                                        property
                        );
                        }
                    }
                }

            if (wasUndefined)
                {
                return new AstType();
                }

            AstType rtype = new AstType(AstType.TYPE_SEQUENCE);
            rtype.m_setType = new AstType(AstType.TYPE_TUPLE);
            rtype.m_setType.newTuple(new AstType(AstType.TYPE_NATURAL1),
                                     stype
            );
            rtype.m_setType.m_tupleIsSeq = true;
            return rtype;
        }
    }

    public class AstBuiltInFunctionX extends AstUnaryOpX
    {
        public AstBuiltInFunctionX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public AstType getType()
        {
            AstType type = m_expression.getType();

            if (type.isUndefined())
                {
                return new AstType();
                }

            if (m_token.m_id == TozeTokenizer.TOKEN_DOM)
                {
                if (type.getType() != AstType.TYPE_SET)
                    {
                    reportTypeError("The argument to the function 'dom' must be a set of tuples",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                if (type.getSetType().getType() != AstType.TYPE_TUPLE)
                    {
                    reportTypeError("The argument to the function 'dom' must be a set of tuples",
                                    m_token,
                                    specObject, property
                    );
                    return new AstType();
                    }
                if (type.getSetType().m_tupleTypes.size() != 2)
                    {
                    reportTypeError("The argument to the function 'dom' must be a tuple of size 2",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                AstType rtype = new AstType(AstType.TYPE_SET);
                rtype.m_setType = (AstType) type.getSetType().m_tupleTypes.get(0);
                return rtype;
                }

            if (m_token.m_id == TozeTokenizer.TOKEN_RAN)
                {
                if (type.getType() != AstType.TYPE_SET)
                    {
                    reportTypeError("The argument to the function 'ran' must be a set of tuples",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                if (type.getSetType().getType() != AstType.TYPE_TUPLE)
                    {
                    reportTypeError("The argument to the function 'ran' must be a set of tuples",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                if (type.getSetType().m_tupleTypes.size() != 2)
                    {
                    reportTypeError("The argument to the function 'ran' must be a tuple of size 2",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                AstType rtype = new AstType(AstType.TYPE_SET);
                rtype.m_setType = (AstType) type.getSetType().m_tupleTypes.get(1);
                return rtype;
                }

            if (m_token.m_id == TozeTokenizer.TOKEN_REV)
                {
                if (type.getType() != AstType.TYPE_SEQUENCE)
                    {
                    reportTypeError("The argument to the function 'rev' must be a sequence",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return type;
                }

            if (m_token.m_id == TozeTokenizer.TOKEN_HEAD)
                {
                if (type.getType() != AstType.TYPE_SEQUENCE)
                    {
                    reportTypeError("The argument to the function 'head' must be a sequence",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return (AstType) type.getSetType().m_tupleTypes.get(1);
//            return type.m_setType;
                }

            if (m_token.m_id == TozeTokenizer.TOKEN_LAST)
                {
                if (type.getType() != AstType.TYPE_SEQUENCE)
                    {
                    reportTypeError("The argument to the function 'last' must be a sequence",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return (AstType) type.getSetType().m_tupleTypes.get(1);
//            return type.m_setType;
                }

            if (m_token.m_id == TozeTokenizer.TOKEN_TAIL)
                {
                if (type.getType() != AstType.TYPE_SEQUENCE)
                    {
                    reportTypeError("The argument to the function 'tail' must be a sequence",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return type;
                }

            if (m_token.m_id == TozeTokenizer.TOKEN_FRONT)
                {
                if (type.getType() != AstType.TYPE_SEQUENCE)
                    {
                    reportTypeError("The argument to the function 'front' must be a sequence",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                return type;
                }

            if ((m_token.m_id == TozeTokenizer.TOKEN_FIRST)
                    || (m_token.m_id == TozeTokenizer.TOKEN_SECOND))
                {
                if ((type.getType() != AstType.TYPE_TUPLE)
                        || (type.m_tupleTypes.size() != 2))
                    {
                    reportTypeError("The argument to " + m_token.m_value + " must be a tuple of size 2",
                                    m_token,
                                    specObject,
                                    property
                    );
                    return new AstType();
                    }
                if (m_token.m_id == TozeTokenizer.TOKEN_FIRST)
                    {
                    return (AstType) type.m_tupleTypes.get(0);
                    }
                return (AstType) type.m_tupleTypes.get(1);
                }

            if (m_token.m_id == TozeTokenizer.TOKEN_HASH)
                {
                if (!type.isSet() && !type.isSequence())
                    {
                    reportTypeError("Argument to '#' must be either a set or a sequence",
                                    m_token,
                                    specObject,
                                    property
                    );
                    }
                return new AstType(AstType.TYPE_NATURAL);
                }

            return new AstType();
        }
    }

    public class AstFunctionX extends AstExpression
    {
        AstExpression m_fexpression;
        AstExpression m_pexpression;

        public AstFunctionX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_fexpression.populateTypeTable(m_stable);
            m_pexpression.populateTypeTable(m_stable);
        }

        public void populateSymbolTable()
        {
            m_fexpression.populateSymbolTable();
            m_pexpression.populateSymbolTable();
        }

        public AstType getType()
        {
            AstType ftype = m_fexpression.getType();
            AstType ptype = m_pexpression.getType();

            if ((ftype.isUndefined())
                    || (ptype.isUndefined()))
                {
                return new AstType();
                }

            /*
             * Check the special case where it looks like an expression function
             * but it is really where a single element of a sequence is being
             * referenced.
             */

            if (ftype.getType() == AstType.TYPE_SEQUENCE)
                {
                if (!ptype.isANumber())
                    {
                    reportTypeError("Subscript to a sequence must be a number",
                                    m_token,
                                    specObject,
                                    property
                    );
                    }
                return (AstType) ftype.getSetType().m_tupleTypes.get(1);
                }

            if ((ftype.getType() != AstType.TYPE_SET)
                    && (ftype.getType() != AstType.TYPE_SEQUENCE))
                {
                reportTypeError("Expression used as a function must evaluate to a set of a tuple",
                                m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            if (ftype.getSetType().getType() != AstType.TYPE_TUPLE)
                {
                reportTypeError("Expression used as a function must evaluate to a tuple",
                                m_token,
                                specObject,
                                property
                );
                return new AstType();
                }
            if (ftype.getSetType().m_tupleTypes.size() < 2)
                {
                reportTypeError("The tuple must be a binary relation",
                                m_token,
                                specObject,
                                property
                );
                return new AstType();
                }

            //if (ptype.getType() == AstType.TYPE_TUPLE)
            if (ptype.isTuple())
                {
                if ((ptype.m_tupleTypes.size() + 1) != ftype.m_setType.m_tupleTypes.size())
                    {
                    reportTypeError("Number of parameters for the function do not match definition.",
                                    m_token,
                                    specObject,
                                    property
                    );
                    }
                int i;
                for (i = 0; i < ptype.m_tupleTypes.size(); i++)
                    {
                    AstType t1 = (AstType) ptype.m_tupleTypes.get(i);
                    AstType t2 = (AstType) ftype.m_setType.m_tupleTypes.get(i);
                    if (!t1.isCompatible(t2))
                        {
                        reportTypeError("Parameter " + (i + 1) + " does not match definition.",
                                        m_token,
                                        specObject,
                                        property
                        );
                        }
                    }
                }
            else
                {
                if (!ptype.isEqual((AstType) ftype.getSetType().m_tupleTypes.get(0)))
                    {
                    reportTypeError("Parameter types do not match function parameters",
                                    m_token,
                                    specObject,
                                    property
                    );
                    }
                }

            List vtmp = ftype.getSetType().m_tupleTypes;
            return (AstType) vtmp.get(vtmp.size() - 1);
        }
    }

    public class AstPredicateX extends AstExpression
    {
        AstPredicate m_predicate;

        public AstPredicateX(SpecObject specObject, String property)
        {
            super(specObject, property);
        }

        public void populateTypeTable(AstSymbolTable stable)
        {
            m_stable = stable;
            m_predicate.populateTypeTable(stable);
        }

        public void populateSymbolTable()
        {
            m_predicate.populateSymbolTable();
        }

        public AstType getType()
        {
            boolean bad = false;
            return new AstType(AstType.TYPE_BOOL);
        }
    }

    /*
     * Infix, Postfix, Prefix
     */
    public class AstPrefixGenericName extends AstBase
    {
        AstDecorations m_decoration;

        public void print(int l)
        {
            print(l, "PrefixGenericName = " + m_token.m_value);
            if (m_decoration != null)
                {
                m_decoration.print(l + 1);
                }
        }
    }

    public class AstInfixGenericName extends AstBase
    {
        AstDecorations m_decoration;

        public void print(int l)
        {
            print(l, "InfixGenericName = " + getName());
            if (m_decoration != null)
                {
                m_decoration.print(l + 1);
                }
        }

        public String getName()
        {
            return m_token.m_value;
        }
    }

    public class AstInfixFunctionName extends AstBase
    {
        AstDecorations m_decoration;

        public void print(int l)
        {
            print(l, m_token.m_value);
            if (m_decoration != null)
                {
                m_decoration.print(l + 1);
                }
        }
    }

    public class AstInfixRelationName extends AstBase
    {
        AstDecorations m_decoration;

        public void print(int l)
        {
            print(l, "InfixRelationName = " + m_token.m_value);
            if (m_decoration != null)
                {
                m_decoration.print(l + 1);
                }
        }
    }

    public class AstPrefixRelationName extends AstBase
    {
        public void print(int l)
        {
            print(l, "PrefixRelationName = " + getName());
        }

        public String getName()
        {
            return m_token.m_value;
        }
    }

    public class AstPostfixFunctionName extends AstBase
    {
        AstDecorations m_decoration;

        public void print(int l)
        {
            print(l, "PrefixFunctionName = " + m_token.m_value);
            m_decoration.print(l + 1);
        }