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);
        }