//Join string + string to string
        public override void CaseABinopExp(ABinopExp node)
        {
            if (node.GetBinop() is APlusBinop)
            {
                PType type = data.ExpTypes[node];
                if (type is ANamedType && ((ANamedType)type).IsPrimitive("string"))
                {
                    PExp other = null;
                    if (node.GetLeft() is ANullExp)
                        other = node.GetRight();
                    if (node.GetRight() is ANullExp)
                        other = node.GetLeft();
                    if (other != null)
                    {
                        node.ReplaceBy(other);
                        other.Apply(this);
                        return;
                    }
                }

                //Case (string + string)
                if (node.GetLeft() is AStringConstExp && node.GetRight() is AStringConstExp)
                {
                    AStringConstExp left = (AStringConstExp) node.GetLeft();
                    AStringConstExp right = (AStringConstExp) node.GetRight();

                    if (!IsJoinAllowed(left.GetStringLiteral().Text, right.GetStringLiteral().Text))
                    {
                        base.CaseABinopExp(node);
                        return;
                    }
                    left.GetStringLiteral().Text = left.GetStringLiteral().Text.Substring(0,
                                                                                          left.GetStringLiteral().Text.
                                                                                              Length - 1);
                    left.GetStringLiteral().Text += right.GetStringLiteral().Text.Substring(1);
                    node.ReplaceBy(left);
                    CaseAStringConstExp(left);
                    return;
                }
                //Case (<exp> + string) + string
                if (node.GetLeft() is ABinopExp && node.GetRight() is AStringConstExp)
                {
                    ABinopExp leftBinop = (ABinopExp) node.GetLeft();
                    if (leftBinop.GetBinop() is APlusBinop && leftBinop.GetRight() is AStringConstExp)
                    {
                        AStringConstExp left = (AStringConstExp) leftBinop.GetRight();
                        AStringConstExp right = (AStringConstExp) node.GetRight();
                        if (!IsJoinAllowed(left.GetStringLiteral().Text, right.GetStringLiteral().Text))
                        {
                            base.CaseABinopExp(node);
                            return;
                        }
                        left.GetStringLiteral().Text = left.GetStringLiteral().Text.Substring(0,
                                                                                              left.GetStringLiteral().
                                                                                                  Text.
                                                                                                  Length - 1);
                        left.GetStringLiteral().Text += right.GetStringLiteral().Text.Substring(1);
                        node.ReplaceBy(leftBinop);
                        CaseABinopExp(leftBinop);
                        return;
                    }
                }
                //Case string + (string + <exp>)
                //Case (<exp> + string) + (string + <exp>)

            }
            //Case (int + int)
            /*if (node.GetLeft() is AIntConstExp && node.GetRight() is AIntConstExp)
            {
                AIntConstExp left = (AIntConstExp) node.GetLeft();
                AIntConstExp right = (AIntConstExp) node.GetRight();

                int a = int.Parse(left.GetIntegerLiteral().Text);
                int b = int.Parse(right.GetIntegerLiteral().Text);

                if (node.GetBinop() is APlusBinop)
                {
                    a += b;
                }
                else if (node.GetBinop() is AMinusBinop)
                {
                    a -= b;
                }
                else if (node.GetBinop() is ATimesBinop)
                {
                    a *= b;
                }
                else if (node.GetBinop() is ADivideBinop)
                {
                    if (b == 0)
                    {
                        base.CaseABinopExp(node);
                        return;
                    }
                    a /= b;
                }
                else
                {
                    base.CaseABinopExp(node);
                    return;
                }

                left.GetIntegerLiteral().Text = a.ToString();
                node.ReplaceBy(left);
                left.Apply(this);
                return;
            }
            //Case (<exp> + int) + int
            if (node.GetLeft() is ABinopExp && node.GetRight() is AIntConstExp && (node.GetBinop() is APlusBinop || node.GetBinop() is AMinusBinop))
            {
                ABinopExp leftBinop = (ABinopExp) node.GetLeft();
                PType leftType = data.ExpTypes[leftBinop];
                if (leftBinop.GetRight() is AIntConstExp && leftType is ANamedType && ((ANamedType) leftType).GetName().Text == "int" &&
                     (leftBinop.GetBinop() is APlusBinop || leftBinop.GetBinop() is AMinusBinop))
                {
                    AIntConstExp left = (AIntConstExp)leftBinop.GetRight();
                    AIntConstExp right = (AIntConstExp)node.GetRight();
                    int a = int.Parse(left.GetIntegerLiteral().Text);
                    int b = int.Parse(right.GetIntegerLiteral().Text);

                    if (node.GetBinop() is APlusBinop)
                    {
                        if (leftBinop.GetBinop() is APlusBinop)
                        {
                            //(<exp> + int) + int
                            int c = a + b;
                            //Test for overflow
                            if (a > 0 && b > 0 && (c < a || c < b) ||
                                a < 0 && b < 0 && (c > a || c > b))
                            {
                                //Don't add them
                                base.CaseABinopExp(node);
                                return;
                            }
                            if (c < 0)
                            {
                                //Change binop to <exp> - c
                                if (c != int.MinValue)
                                {
                                    c = -c;
                                    leftBinop.SetBinop(new AMinusBinop(new TMinus("-")));
                                }
                            }
                            //Replace node with leftbinop
                            left.GetIntegerLiteral().Text = c.ToString();
                            node.ReplaceBy(leftBinop);
                            leftBinop.Apply(this);
                            return;
                        }
                        else
                        {
                            //(<exp> - int) + int
                            int c = b - a;
                            //Test for overflow
                            if (a < 0 && b > 0 && (c < a || c < b) ||
                                a > 0 && b < 0 && (c > a || c > b))
                            {
                                //Don't add them
                                base.CaseABinopExp(node);
                                return;
                            }
                            if (c > 0 || c == int.MinValue)
                            {
                                //Change binop to <exp> + c
                                leftBinop.SetBinop(new APlusBinop(new TPlus("+")));

                            }
                            else
                                c = -c;
                            //Replace node with leftbinop
                            left.GetIntegerLiteral().Text = c.ToString();
                            node.ReplaceBy(leftBinop);
                            leftBinop.Apply(this);
                            return;
                        }
                    }
                    else
                    {
                        if (leftBinop.GetBinop() is APlusBinop)
                        {
                            //(<exp> + int) - int
                            //ALso need to consider <exp> in the other position, and int on the other side of the binop
                            //Make a more general algorithm
                        }
                        else
                        {

                        }
                    }
                }
            }*/
            base.CaseABinopExp(node);
        }
        public override void OutABinopExp(ABinopExp node)
        {
            if (node.Parent() is ABinopExp || node.Parent() is AUnopExp)
            {
                AParenExp paren = new AParenExp();
                node.ReplaceBy(paren);
                paren.SetExp(node);

                finalTrans.data.ExpTypes[paren] = finalTrans.data.ExpTypes[node];
            }
            base.OutABinopExp(node);
        }
            public override void CaseABinopExp(ABinopExp node)
            {
                if (node.GetBinop() is AEqBinop && node.GetRight() is ANullExp && data.ExpTypes[node.GetLeft()] is APointerType)
                {
                    //We have a null check
                    APointerType pointerType = (APointerType)data.ExpTypes[node.GetLeft()];
                    AMethodDecl nullCheckMethod = CreateNullCheckMethod(node, pointerType.GetType(), data);

                    ASimpleInvokeExp invoke = new ASimpleInvokeExp(new TIdentifier("IsNull"), new ArrayList(){node.GetLeft()});
                    node.ReplaceBy(invoke);

                    data.ExpTypes[invoke] = new ANamedType(new TIdentifier("bool"), null);
                    data.SimpleMethodLinks[invoke] = nullCheckMethod;
                    CaseASimpleInvokeExp(invoke);
                    return;
                }
                base.CaseABinopExp(node);
            }
        public override void OutABinopExp(ABinopExp node)
        {
            PBinop binop = node.GetBinop();
            PExp left = node.GetLeft();
            PType leftType = data.ExpTypes[left];
            string leftTypeString = Util.TypeToString(leftType);
            PExp right = node.GetRight();
            PType rightType = data.ExpTypes[right];
            string rightTypeString = Util.TypeToString(rightType);

            bool wasDefined = false;
            Token token = null;
            while (true)
            {
                if (binop is APlusBinop)
                {
                    token = ((APlusBinop) binop).GetToken();
                    //Check that types are okay for +
                    if (!new[] {"int", "fixed", "string", "text", "byte", "point"}.Any(c => c == leftTypeString))
                    {
                        errors.Add(new ErrorCollection.Error(token, currentSourceFile,
                                                             LocRM.GetString("ErrorText103") + leftTypeString));
                        throw new ParserException(null, null);
                    }
                    if (!new[] {"int", "fixed", "string", "text", "byte", "point"}.Any(c => c == rightTypeString))
                    {
                        errors.Add(new ErrorCollection.Error(token, currentSourceFile,
                                                             LocRM.GetString("ErrorText103") + rightTypeString));
                        throw new ParserException(null, null);
                    }
                    //If you are using string or text, both sides must be same type
                    if ((leftTypeString == "string" && rightTypeString != "string") ||
                        (leftTypeString == "text" && rightTypeString != "text") ||
                        (leftTypeString == "point" && rightTypeString != "point") ||
                        (rightTypeString == "string" && leftTypeString != "string") ||
                        (rightTypeString == "text" && leftTypeString != "text") ||
                        (rightTypeString == "point" && leftTypeString != "point"))
                    {
                        if (ImplicitAssignable(leftType, rightType))
                        {
                            ANamedType namedTo = (ANamedType) rightType;
                            ACastExp cast = new ACastExp(new TLParen("("),
                                                         new ANamedType(
                                                             new TIdentifier(((AAName) namedTo.GetName()).AsString()),
                                                             null), node.GetLeft());
                            node.SetLeft(cast);
                            OutACastExp(cast);
                            leftType = rightType;
                        }
                        else if (ImplicitAssignable(rightType, leftType))
                        {
                            ANamedType namedTo = (ANamedType) leftType;
                            ACastExp cast = new ACastExp(new TLParen("("),
                                                         new ANamedType(
                                                             new TIdentifier(((AAName) namedTo.GetName()).AsString()),
                                                             null), node.GetRight());
                            node.SetRight(cast);
                            OutACastExp(cast);
                            rightType = leftType;
                        }
                        else
                        {
                            //Not valid
                            break;
                        }
                    }
                    wasDefined = true;
                    PType type = leftType;
                    if (rightTypeString == "fixed")
                        type = rightType;
                    data.ExpTypes[node] = type;
                }
                else if (binop is AMinusBinop || binop is ATimesBinop || binop is ADivideBinop || binop is AModuloBinop)
                {
                    token = null;
                    if (binop is AMinusBinop) token = ((AMinusBinop) binop).GetToken();
                    else if (binop is ATimesBinop) token = ((ATimesBinop) binop).GetToken();
                    else if (binop is ADivideBinop) token = ((ADivideBinop) binop).GetToken();
                    else if (binop is AModuloBinop) token = ((AModuloBinop) binop).GetToken();

                    //Check that types are okay for whatever
                    if (!new[] {"int", "fixed", "byte", "point"}.Any(c => c == leftTypeString))
                    {
                        //Not valid
                        break;
                    }
                    if (!new[] {"int", "fixed", "byte", "point"}.Any(c => c == rightTypeString))
                    {
                        //Not valid
                        break;
                    }
                    if ((leftTypeString == "point" || rightTypeString == "point") &&
                        !(leftTypeString == "point" && rightTypeString == "point" && binop is AMinusBinop))
                    {
                        //Not valid
                        break;
                    }
                    wasDefined = true;
                    PType type = leftType;
                    if (rightTypeString == "fixed")
                        type = rightType;
                    if (rightTypeString == "int" && leftTypeString == "byte")
                        type = rightType;
                    data.ExpTypes[node] = type;
                }
                else if (binop is AEqBinop || binop is ANeBinop || binop is ALtBinop || binop is ALeBinop ||
                         binop is AGtBinop || binop is AGeBinop)
                {
                    token = null;
                    if (binop is AEqBinop) token = ((AEqBinop) binop).GetToken();
                    else if (binop is ANeBinop) token = ((ANeBinop) binop).GetToken();
                    else if (binop is ALtBinop) token = ((ALtBinop) binop).GetToken();
                    else if (binop is ALeBinop) token = ((ALeBinop) binop).GetToken();
                    else if (binop is AGtBinop) token = ((AGtBinop) binop).GetToken();
                    else if (binop is AGeBinop) token = ((AGeBinop) binop).GetToken();

                    //Unless types are int and fixed, they must be the same type, or null and a nullable type
                    if (leftTypeString == "void" || rightTypeString == "void" ||
                        !(
                             GalaxyKeywords.NullablePrimitives.words.Any(s => s == leftTypeString) &&
                             rightTypeString == "null" ||
                             leftTypeString == "null" &&
                             GalaxyKeywords.NullablePrimitives.words.Any(s => s == rightTypeString) ||
                             (leftTypeString == "int" || leftTypeString == "fixed" || leftTypeString == "byte") &&
                             (rightTypeString == "int" || rightTypeString == "fixed" || rightTypeString == "byte") ||
                             leftTypeString == rightTypeString && !(IsDynamic(leftType) || IsDynamic(rightType)) ||
                             (binop is AEqBinop || binop is ANeBinop) &&
                             (
                                 leftTypeString == rightTypeString ||
                                 leftTypeString == "null" && IsDynamic(rightType) ||
                                 IsDynamic(leftType) && rightTypeString == "null" ||
                                 Util.TypesEqual(leftType, rightType, data)
                             ) ||
                             leftType is ANamedType && data.DelegateTypeLinks.ContainsKey((ANamedType) leftType) &&
                             (rightTypeString == "null" ||
                              rightType is ANamedType && data.DelegateTypeLinks.ContainsKey((ANamedType) rightType)) ||
                             rightType is ANamedType && data.DelegateTypeLinks.ContainsKey((ANamedType) rightType) &&
                             leftTypeString == "null"
                         )
                        )
                    {

                        //Not valid
                        break;

                    }
                    wasDefined = true;
                    data.ExpTypes[node] = new ANamedType(new TIdentifier("bool"), null);
                }
                else if (binop is AAndBinop || binop is AOrBinop || binop is AXorBinop || binop is ALBitShiftBinop ||
                         binop is ARBitShiftBinop)
                {
                    token = null;
                    if (binop is AAndBinop) token = ((AAndBinop) binop).GetToken();
                    else if (binop is AOrBinop) token = ((AOrBinop) binop).GetToken();
                    else if (binop is AXorBinop) token = ((AXorBinop) binop).GetToken();
                    else if (binop is ALBitShiftBinop) token = ((ALBitShiftBinop) binop).GetToken();
                    else if (binop is ARBitShiftBinop) token = ((ARBitShiftBinop) binop).GetToken();

                    if (
                        !((leftTypeString == "int" || leftTypeString == "byte") &&
                          (rightTypeString == "int" || rightTypeString == "byte") &&
                          (binop is ALBitShiftBinop || binop is ARBitShiftBinop ||
                           leftTypeString == rightTypeString)))
                    {
                        if (rightTypeString == "int" && leftTypeString == "byte" && left is AIntConstExp)
                        {
                            data.ExpTypes[left] =
                                leftType = new ANamedType(new TIdentifier("int"), null);
                            leftTypeString = "int";
                        }
                        else if (leftTypeString == "int" && rightTypeString == "byte" && right is AIntConstExp)
                        {
                            data.ExpTypes[right] =
                                rightType = new ANamedType(new TIdentifier("int"), null);
                            rightTypeString = "int";
                        }
                        else
                        {
                            //Not valid
                            break;
                        }
                    }
                    wasDefined = true;
                    data.ExpTypes[node] = leftType;
                    if (rightTypeString == "int")
                        data.ExpTypes[node] = rightType;
                }
                else if (binop is ALazyAndBinop || binop is ALazyOrBinop)
                {
                    token = null;
                    if (binop is ALazyAndBinop) token = ((ALazyAndBinop) binop).GetToken();
                    else if (binop is ALazyOrBinop) token = ((ALazyOrBinop) binop).GetToken();

                    if (leftTypeString != "bool" || rightTypeString != "bool")
                    {

                        errors.Add(new ErrorCollection.Error(token, currentSourceFile,
                                                             token.Text + LocRM.GetString("ErrorText104") +
                                                             token.Text +
                                                             " bool). Got (" +
                                                             leftTypeString + " " + token.Text + " " +
                                                             rightTypeString + ")"));
                        throw new ParserException(null, null);
                    }
                    wasDefined = true;
                    data.ExpTypes[node] = leftType;
                }
                else
                    throw new Exception("Unexpected binop (This should never happen)");
                break;
            }

            List<AMethodDecl> possibleOperators = new List<AMethodDecl>();
            List<IList> visibleDecls = Util.GetVisibleDecls(node, true);
            List<string> currentNamespace = Util.GetFullNamespace(node);
            AASourceFile currentFile = Util.GetAncestor<AASourceFile>(node);
            foreach (IList declList in visibleDecls)
            {
                bool sameNS = false;
                bool sameFile = false;
                if (declList.Count > 0)
                {
                    sameNS = Util.NamespacesEquals(currentNamespace, Util.GetFullNamespace((PDecl) declList[0]));
                    sameFile = currentFile == Util.GetAncestor<AASourceFile>((PDecl) declList[0]);
                }
                foreach (PDecl decl in declList)
                {
                    if (decl is AMethodDecl)
                    {
                        AMethodDecl method = (AMethodDecl) decl;
                        if (method.GetName().Text == token.Text)
                        {
                            if (method.GetVisibilityModifier() is APrivateVisibilityModifier && !sameNS)
                                continue;
                            if (method.GetStatic() != null && !sameFile)
                                continue;
                            //Check that parameters are assignable
                            bool add = true;
                            bool matchImplicit = false;
                            List<PType> argTypes = new List<PType>(){leftType, rightType};
                            for (int i = 0; i < argTypes.Count; i++)
                            {
                                PType argType = argTypes[i];
                                AALocalDecl formal = (AALocalDecl)method.GetFormals()[i];
                                PType formalType = formal.GetType();
                                if (formal.GetOut() != null && !Assignable(formalType, argType)
                                    ||
                                    formal.GetRef() != null &&
                                    !(Assignable(argType, formalType) && Assignable(formalType, argType))
                                    ||
                                    formal.GetOut() == null && formal.GetRef() == null &&
                                    !Assignable(argType, formalType))
                                {
                                    add = false;
                                    if (formal.GetOut() == null && formal.GetRef() == null &&
                                        ImplicitAssignable(argType, formalType))
                                    {
                                        matchImplicit = true;
                                    }
                                    else
                                    {
                                        matchImplicit = false;
                                        break;
                                    }
                                }
                            }
                            if (!add && !matchImplicit)
                                continue;
                            if (add)
                                possibleOperators.Add(method);
                        }
                    }
                }
            }

            if (possibleOperators.Count == 0 && !wasDefined)
            {
                errors.Add(new ErrorCollection.Error(token, LocRM.GetString("ErrorText105") + leftTypeString + " " + token.Text + " " + rightTypeString + ")"));
                throw new ParserException(token, "TypeChecking.OutABinopExp");
            }

            if (possibleOperators.Count + (wasDefined ? 1 : 0) > 1)
            {
                List<ErrorCollection.Error> subErrors = new List<ErrorCollection.Error>();
                foreach (AMethodDecl method in possibleOperators)
                {
                    subErrors.Add(new ErrorCollection.Error(method.GetName(), LocRM.GetString("ErrorText106")));
                }
                if (wasDefined)
                    subErrors.Add(new ErrorCollection.Error(token, LocRM.GetString("ErrorText107") + token.Text));
                errors.Add(new ErrorCollection.Error(token, LocRM.GetString("ErrorText108") + leftTypeString + " " + token.Text + " " + rightTypeString + LocRM.GetString("ErrorText109"), false, subErrors.ToArray()));
                throw new ParserException(token, "TypeChecking.OutABinopExp");
            }

            if (wasDefined)
                return;

            AMethodDecl op = possibleOperators[0];
            ASimpleInvokeExp replacer = new ASimpleInvokeExp(new TIdentifier(op.GetName().Text), new ArrayList(){node.GetLeft(), node.GetRight()});
            node.ReplaceBy(replacer);
            data.SimpleMethodLinks[replacer] = op;
            data.ExpTypes[replacer] = op.GetReturnType();

            //base.OutABinopExp(node);
        }
 public override void OutABinopExp(ABinopExp node)
 {
     if (node.GetBinop() is AEqBinop || node.GetBinop() is ANeBinop)
     {
         if (node.GetLeft() is ANullExp || node.GetRight() is ANullExp)
         {
             if (node.GetLeft() is ANullExp)
             {
                 //Swap left and right
                 PExp temp = node.GetLeft();
                 node.SetLeft(node.GetRight());
                 node.SetRight(temp);
             }
             PExp exp = node.GetLeft();
             PType type = data.ExpTypes[exp];
             if (type is APointerType)
             {
                 if (node.GetBinop() is ANeBinop)
                 {
                     //Convert a != null to !(a == null)
                     AUnopExp unop = new AUnopExp(new AComplementUnop(new TComplement("!")), null);
                     node.ReplaceBy(unop);
                     unop.SetExp(node);
                     node.SetBinop(new AEqBinop(new TEq("==")));
                     data.ExpTypes[unop] = new ANamedType(new TIdentifier("bool"), null);
                 }
                 if (Util.IsIntPointer(node, ((APointerType)type).GetType(), data))
                 {
                     bool add = true;
                     foreach (PType pType in TypesWithIdentifierArray)
                     {
                         if (Util.TypesEqual(((APointerType)type).GetType(), pType, data))
                         {
                             add = false;
                             break;
                         }
                     }
                     if (add)
                         TypesWithIdentifierArray.Add(((APointerType)type).GetType());
                 }
             }
         }
     }
 }