public Type(string btstr, int dim)
     : this(TypeUtils.getType(btstr), dim)
 {
 }
        /*-----------------------------------------------------------------------------
         * Function: OpType
         * Description: Returns the Type of operating this with right with operation op
         *---------------------------------------------------------------------------*/
        public Type OpType(string op, Type right)
        {
            // recursive? -> returns the other
            if (this.IsRecursive)
            {
                return(new Type(right.btype, right.dim));
            }
            else if (right.IsRecursive)
            {
                return(new Type(this.btype, this.dim));
            }

            // 0-dim? handle basic operands
            if (this.dim == 0 && right.dim == 0)
            {
                // Basic zero-dimensional types
                switch (op)
                {
                case "^":
                    // numeric ^ numeric -> float
                    if (this.IsNumeric && right.IsNumeric)
                    {
                        return(new Type(BasicType.FLOAT, 0));
                    }
                    else
                    {
                        // No idea what to do with str power bool
                        // or something else
                        return(Type.BASE_UNDEFINED.Clone());
                    }

                case "+":
                case "-":           // Corner case == one of them is char
                                    // -- can sum/sub with int and returns
                                    // char
                    // char + int -> char
                    // int + char -> char
                    if ((this.btype == BasicType.CHAR && right.btype == BasicType.INT) ||
                        (this.btype == BasicType.INT && right.btype == BasicType.CHAR))
                    {
                        return(new Type(BasicType.CHAR, 0));
                    }
                    else if (this.IsNumeric && right.IsNumeric)
                    {
                        // numeric + numeric -> {int, float}
                        return(new Type(TypeUtils.mathOpMaybeUpcast(this.btype, right.btype), 0));
                    }
                    else
                    {
                        return(Type.BASE_UNDEFINED.Clone());
                    }

                case "/":
                case "*":
                    // numeric * numeric -> {int, float}
                    if (this.IsNumeric && right.IsNumeric)
                    {
                        return(new Type(TypeUtils.mathOpMaybeUpcast(this.btype, right.btype), 0));
                    }
                    else
                    {
                        return(Type.BASE_UNDEFINED.Clone());
                    }

                case "::":
                    // With 0-dimension strings , :: is string
                    // concat, i.e. str :: str -> str
                    if (this.btype == right.btype && this.btype == BasicType.STR)
                    {
                        return(new Type(BasicType.STR, 0));
                    }
                    else
                    {
                        // Invalid op
                        return(Type.BASE_UNDEFINED.Clone());
                    }

                default:
                    return(new Type(BasicType.UNDEFINED, 0));
                }
            }
            else   /*multi-dim*/
            if (op == "::" &&
                this.btype == right.btype &&
                this.dim == right.dim)
            {
                // any[]... :: any[]... -> any[]...
                // as long as types are equal and dimensions are the same
                return(new Type(this.btype, this.dim));
            }
            else
            {
                return(Type.BASE_UNDEFINED.Clone());
            }
        }