Equals() public method

public Equals ( CiType obj ) : bool
obj CiType
return bool
Beispiel #1
0
        CiMaybeAssign Coerce(CiMaybeAssign expr, CiType expected)
        {
            CiType got = expr.Type;

            if (expected.Equals(got))
            {
                return(expr);
            }
            if (expected == CiIntType.Value && got == CiByteType.Value)
            {
                CiConstExpr konst = expr as CiConstExpr;
                if (konst != null)
                {
                    return(new CiConstExpr((object)(int)(byte)konst.Value));
                }
                CiCondExpr cond = expr as CiCondExpr;
                if (cond != null && (cond.OnTrue is CiConstExpr || cond.OnFalse is CiConstExpr))
                {
                    // avoid ((foo ? 1 : 0) & 0xff) in Java
                    return(Coerce(cond, expected));
                }
                if (expr is CiArrayAccess)
                {
                    CiConstAccess ca = ((CiArrayAccess)expr).Array as CiConstAccess;
                    if (ca != null && ca.Const.Is7Bit)
                    {
                        return(expr);
                    }
                }
                return(new CiCoercion {
                    ResultType = expected, Inner = expr
                });
            }
            if (expected == CiByteType.Value && got == CiIntType.Value)
            {
                CiConstExpr konst = expr as CiConstExpr;
                if (konst != null)
                {
                    return(new CiConstExpr((object)(byte)(int)konst.Value));
                }
                return(new CiCoercion {
                    ResultType = expected, Inner = expr
                });
            }
            if (expected == CiStringPtrType.Value && (got == CiType.Null || got is CiStringType))
            {
                return(expr);
            }
            if (expected is CiStringStorageType && got is CiStringType)
            {
                return(expr);
            }
            if (expected is CiClassType)
            {
                if (got == CiType.Null)
                {
                    return(expr);
                }
                if (Extends(got, ((CiClassType)expected).Class))
                {
                    if (expr is CiCondExpr)
                    {
                        // C doesn't like &(cond ? foo : bar)
                        return(Coerce((CiCondExpr)expr, expected));
                    }
                    return(new CiCoercion {
                        ResultType = expected, Inner = expr
                    });
                }
            }
            if (expected is CiArrayPtrType)
            {
                if (got == CiType.Null)
                {
                    return(expr);
                }
                CiArrayType gotArray = got as CiArrayType;
                if (got != null && ((CiArrayPtrType)expected).ElementType.Equals(gotArray.ElementType))
                {
                    return new CiCoercion {
                               ResultType = expected, Inner = expr
                    }
                }
                ;
            }
            throw new ResolveException("Expected {0}, got {1}", expected, got);
        }

        CiExpr Coerce(CiExpr expr, CiType expected)
        {
            return((CiExpr)Coerce((CiMaybeAssign)expr, expected));
        }

        object ResolveConstExpr(CiExpr expr, CiType type)
        {
            expr = Coerce(Resolve(expr), type);
            CiConstExpr ce = expr as CiConstExpr;

            if (ce == null)
            {
                throw new ResolveException("{0} is not constant", expr);
            }
            return(ce.Value);
        }

        object ResolveConstInitializer(ref CiType type, object value)
        {
            if (type is CiArrayType)
            {
                object[] array = value as object[];
                if (array == null)
                {
                    return(value);
                }
                CiType elementType = ((CiArrayType)type).ElementType;
                if (type is CiArrayStorageType)
                {
                    int expected = ((CiArrayStorageType)type).Length;
                    if (array.Length != expected)
                    {
                        throw new ResolveException("Expected {0} array elements, got {1}", expected, array.Length);
                    }
                }
                else
                {
                    type = new CiArrayStorageType {
                        ElementType = elementType, Length = array.Length
                    };
                }
                Array dest = Array.CreateInstance(elementType.DotNetType, array.Length);
                for (int i = 0; i < array.Length; i++)
                {
                    dest.SetValue(ResolveConstInitializer(ref elementType, array[i]), i);
                }
                return(dest);
            }
            if (value is CiExpr)
            {
                return(ResolveConstExpr((CiExpr)value, type));
            }
            return(value);
        }

        void ICiSymbolVisitor.Visit(CiEnum enu)
        {
        }
Beispiel #2
0
        CiExpr ICiExprVisitor.Visit(CiSymbolAccess expr)
        {
            CiSymbol symbol = Lookup(expr);

            if (symbol is CiVar)
            {
                return new CiVarAccess {
                           Var = (CiVar)symbol
                }
            }
            ;
            if (symbol is CiConst)
            {
                return(GetValue((CiConst)symbol));
            }
            if (symbol is CiField)
            {
                if (this.CurrentMethod.CallType == CiCallType.Static)
                {
                    throw new ResolveException("Cannot access field from a static method");
                }
                symbol.Accept(this);
                return(CreateFieldAccess(new CiVarAccess {
                    Var = this.CurrentMethod.This
                }, (CiField)symbol));
            }
            throw new ResolveException("Invalid expression");
        }

        CiExpr ICiExprVisitor.Visit(CiUnknownMemberAccess expr)
        {
            if (expr.Parent is CiSymbolAccess)
            {
                CiSymbol symbol = Lookup((CiSymbolAccess)expr.Parent);
                if (symbol is CiEnum)
                {
                    return(new CiConstExpr(((CiEnum)symbol).LookupMember(expr.Name)));
                }
                if (symbol is CiClass)
                {
                    symbol = ((CiClass)symbol).Members.Lookup(expr.Name);
                    if (symbol is CiConst)
                    {
                        return(GetValue((CiConst)symbol));
                    }
                    throw new ResolveException("Cannot access " + expr.Name);
                }
            }
            CiExpr   parent = Resolve(expr.Parent);
            CiSymbol member = parent.Type.LookupMember(expr.Name);

            member.Accept(this);
            if (member is CiField)
            {
                return(CreateFieldAccess(parent, (CiField)member));
            }
            if (member is CiProperty)
            {
                CiProperty prop = (CiProperty)member;
                if (parent is CiConstExpr)
                {
                    if (prop == CiLibrary.LowByteProperty)
                    {
                        return(new CiConstExpr((byte)GetConstInt(parent)));
                    }
                    if (prop == CiLibrary.SByteProperty)
                    {
                        return(new CiConstExpr((int)(sbyte)GetConstInt(parent)));
                    }
                    if (prop == CiLibrary.StringLengthProperty)
                    {
                        return(new CiConstExpr(((string)((CiConstExpr)parent).Value).Length));
                    }
                }
                return(new CiPropertyAccess {
                    Obj = parent, Property = prop
                });
            }
            if (member is CiConst)
            {
                return(new CiConstExpr(((CiConst)member).Value));
            }
            throw new ResolveException(member.ToString());
        }

        CiExpr ICiExprVisitor.Visit(CiIndexAccess expr)
        {
            CiExpr parent = Resolve(expr.Parent);
            CiExpr index  = Coerce(Resolve(expr.Index), CiIntType.Value);

            if (parent.Type is CiArrayType)
            {
                return new CiArrayAccess {
                           Array = parent, Index = index
                }
            }
            ;
            if (parent.Type is CiStringType)
            {
                if (parent is CiConstExpr && index is CiConstExpr)
                {
                    string s = (string)((CiConstExpr)parent).Value;
                    int    i = GetConstInt(index);
                    if (i < s.Length)
                    {
                        return(new CiConstExpr((int)s[i]));
                    }
                }
                return(new CiMethodCall {
                    Method = CiLibrary.CharAtMethod,
                    Obj = parent,
                    Arguments = new CiExpr[1] {
                        index
                    }
                });
            }
            throw new ResolveException("Indexed object is neither array or string");
        }

        void ICiSymbolVisitor.Visit(CiDelegate del)
        {
            del.ReturnType = Resolve(del.ReturnType);
            foreach (CiParam param in del.Params)
            {
                param.Type = Resolve(param.Type);
            }
        }

        CiType ICiTypeVisitor.Visit(CiDelegate del)
        {
            ((ICiSymbolVisitor)this).Visit(del);
            return(del);
        }

        void ResolveObj(CiMethodCall expr)
        {
            if (expr.Obj is CiSymbolAccess)
            {
                // Foo(...)
                CiMethod method = Lookup((CiSymbolAccess)expr.Obj) as CiMethod;
                if (method != null)
                {
                    expr.Method = method;
                    if (method.CallType == CiCallType.Static)
                    {
                        expr.Obj = null;
                    }
                    else
                    {
                        if (this.CurrentMethod.CallType == CiCallType.Static)
                        {
                            throw new ResolveException("Cannot call instance method from a static method");
                        }
                        expr.Obj = Coerce(new CiVarAccess {
                            Var = this.CurrentMethod.This
                        }, new CiClassPtrType {
                            Class = method.Class
                        });
                        CheckCopyPtr(method.This.Type, expr.Obj);
                    }
                    return;
                }
            }
            else if (expr.Obj is CiUnknownMemberAccess)
            {
                // ???.Foo(...)
                CiUnknownMemberAccess uma = (CiUnknownMemberAccess)expr.Obj;
                if (uma.Parent is CiSymbolAccess)
                {
                    CiClass klass = Lookup((CiSymbolAccess)uma.Parent) as CiClass;
                    if (klass != null)
                    {
                        // Class.Foo(...)
                        CiMethod method = klass.Members.Lookup(uma.Name) as CiMethod;
                        if (method != null)
                        {
                            if (method.CallType != CiCallType.Static)
                            {
                                throw new ResolveException("{0} is a non-static method", method.Name);
                            }
                            expr.Method = method;
                            expr.Obj    = null;
                            return;
                        }
                    }
                }
                CiExpr obj = Resolve(uma.Parent);
                {
                    CiMethod method = obj.Type.LookupMember(uma.Name) as CiMethod;
                    if (method != null)
                    {
                        // obj.Foo(...)
                        if (method.CallType == CiCallType.Static)
                        {
                            throw new ResolveException("{0} is a static method", method.Name);
                        }
                        if (method.This != null)
                        {
                            // user-defined method
                            CheckCopyPtr(method.This.Type, obj);
                            obj = Coerce(obj, new CiClassPtrType {
                                Class = method.Class
                            });
                        }
                        expr.Method = method;
                        expr.Obj    = obj;
                        return;
                    }
                }
            }
            expr.Obj = Resolve(expr.Obj);
            if (!(expr.Obj.Type is CiDelegate))
            {
                throw new ResolveException("Invalid call");
            }
            if (expr.Obj.HasSideEffect)
            {
                throw new ResolveException("Side effects not allowed in delegate call");
            }
        }

        void CoerceArguments(CiMethodCall expr)
        {
            expr.Signature.Accept(this);
            CiParam[] paramz = expr.Signature.Params;
            if (expr.Arguments.Length != paramz.Length)
            {
                throw new ResolveException("Invalid number of arguments for {0}, expected {1}, got {2}", expr.Signature.Name, paramz.Length, expr.Arguments.Length);
            }
            for (int i = 0; i < paramz.Length; i++)
            {
                CiExpr arg = Resolve(expr.Arguments[i]);
                CheckCopyPtr(paramz[i].Type, arg);
                expr.Arguments[i] = Coerce(arg, paramz[i].Type);
            }
        }

        CiExpr ICiExprVisitor.Visit(CiMethodCall expr)
        {
            ResolveObj(expr);
            CoerceArguments(expr);
            if (expr.Method != null && expr.Method != this.CurrentMethod)
            {
                if (expr.Method.IsMutator)
                {
                    MarkWritable(expr.Obj);
                }
                expr.Method.CalledBy.Add(this.CurrentMethod);
                this.CurrentMethod.Calls.Add(expr.Method);
            }
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiUnaryExpr expr)
        {
            CiExpr resolved;

            if (expr.Op == CiToken.Increment || expr.Op == CiToken.Decrement)
            {
                resolved = ResolveLValue(expr.Inner);
            }
            else
            {
                resolved = Resolve(expr.Inner);
            }
            expr.Inner = Coerce(resolved, CiIntType.Value);
            if (expr.Op == CiToken.Minus && expr.Inner is CiConstExpr)
            {
                return(new CiConstExpr(-GetConstInt(expr.Inner)));
            }
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiCondNotExpr expr)
        {
            expr.Inner = Coerce(Resolve(expr.Inner), CiBoolType.Value);
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiPostfixExpr expr)
        {
            expr.Inner = Coerce(ResolveLValue(expr.Inner), CiIntType.Value);
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiBinaryExpr expr)
        {
            CiExpr left  = Resolve(expr.Left);
            CiExpr right = Resolve(expr.Right);

            if (expr.Op == CiToken.Plus && (left.Type is CiStringType || right.Type is CiStringType))
            {
                if (!(left is CiConstExpr && right is CiConstExpr))
                {
                    throw new ResolveException("String concatenation allowed only for constants. Consider using +=");
                }
                string a = GetConstString(left);
                string b = GetConstString(right);
                return(new CiConstExpr(a + b));
            }
            left  = Coerce(left, CiIntType.Value);
            right = Coerce(right, CiIntType.Value);
            if (right is CiConstExpr)
            {
                int b = GetConstInt(right);
                if (left is CiConstExpr)
                {
                    int a = GetConstInt(left);
                    switch (expr.Op)
                    {
                    case CiToken.Asterisk: a *= b; break;

                    case CiToken.Slash: a /= b; break;

                    case CiToken.Mod: a %= b; break;

                    case CiToken.And: a &= b; break;

                    case CiToken.ShiftLeft: a <<= b; break;

                    case CiToken.ShiftRight: a >>= b; break;

                    case CiToken.Plus: a += b; break;

                    case CiToken.Minus: a -= b; break;

                    case CiToken.Or: a |= b; break;

                    case CiToken.Xor: a ^= b; break;
                    }
                    return(new CiConstExpr(a));
                }
                if (expr.Op == CiToken.And && (b & ~0xff) == 0)
                {
                    CiCoercion c = left as CiCoercion;
                    if (c != null && c.Inner.Type == CiByteType.Value)
                    {
                        left = (CiExpr)c.Inner;
                    }
                }
            }
            expr.Left  = left;
            expr.Right = right;
            return(expr);
        }

        static CiType FindCommonType(CiExpr expr1, CiExpr expr2)
        {
            CiType type1 = expr1.Type;
            CiType type2 = expr2.Type;

            if (type1.Equals(type2))
            {
                return(type1);
            }
            if ((type1 == CiIntType.Value && type2 == CiByteType.Value) ||
                (type1 == CiByteType.Value && type2 == CiIntType.Value))
            {
                return(CiIntType.Value);
            }
            CiType type = type1.Ptr;

            if (type != null)
            {
                return(type);        // stg, ptr || stg, null
            }
            type = type2.Ptr;
            if (type != null)
            {
                return(type);        // ptr, stg || null, stg
            }
            if (type1 != CiType.Null)
            {
                return(type1);        // ptr, null
            }
            if (type2 != CiType.Null)
            {
                return(type2);        // null, ptr
            }
            throw new ResolveException("Incompatible types");
        }

        CiExpr ICiExprVisitor.Visit(CiBoolBinaryExpr expr)
        {
            CiExpr left  = Resolve(expr.Left);
            CiExpr right = Resolve(expr.Right);
            CiType type;

            switch (expr.Op)
            {
            case CiToken.CondAnd:
            case CiToken.CondOr:
                type = CiBoolType.Value;
                break;

            case CiToken.Equal:
            case CiToken.NotEqual:
                type = FindCommonType(left, right);
                break;

            default:
                type = CiIntType.Value;
                break;
            }
            expr.Left  = Coerce(left, type);
            expr.Right = Coerce(right, type);
            CiConstExpr cleft = expr.Left as CiConstExpr;

            if (cleft != null)
            {
                switch (expr.Op)
                {
                case CiToken.CondAnd:
                    return((bool)cleft.Value ? expr.Right : new CiConstExpr(false));

                case CiToken.CondOr:
                    return((bool)cleft.Value ? new CiConstExpr(true) : expr.Right);

                case CiToken.Equal:
                case CiToken.NotEqual:
                    CiConstExpr cright = expr.Right as CiConstExpr;
                    if (cright != null)
                    {
                        bool eq = object.Equals(cleft.Value, cright.Value);
                        return(new CiConstExpr(expr.Op == CiToken.Equal ? eq : !eq));
                    }
                    break;

                default:
                    if (expr.Right is CiConstExpr)
                    {
                        int  a = GetConstInt(cleft);
                        int  b = GetConstInt(expr.Right);
                        bool result;
                        switch (expr.Op)
                        {
                        case CiToken.Less: result = a < b; break;

                        case CiToken.LessOrEqual: result = a <= b; break;

                        case CiToken.Greater: result = a > b; break;

                        case CiToken.GreaterOrEqual: result = a >= b; break;

                        default: return(expr);
                        }
                        return(new CiConstExpr(result));
                    }
                    break;
                }
            }
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiCondExpr expr)
        {
            expr.Cond = Coerce(Resolve(expr.Cond), CiBoolType.Value);
            CiExpr expr1 = Resolve(expr.OnTrue);
            CiExpr expr2 = Resolve(expr.OnFalse);

            expr.ResultType = FindCommonType(expr1, expr2);
            expr.OnTrue     = Coerce(expr1, expr.ResultType);
            expr.OnFalse    = Coerce(expr2, expr.ResultType);
            CiConstExpr konst = expr.Cond as CiConstExpr;

            if (konst != null)
            {
                return((bool)konst.Value ? expr.OnTrue : expr.OnFalse);
            }
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiBinaryResourceExpr expr)
        {
            string           name = (string)ResolveConstExpr(expr.NameExpr, CiStringPtrType.Value);
            CiBinaryResource resource;

            if (!this.BinaryResources.TryGetValue(name, out resource))
            {
                resource         = new CiBinaryResource();
                resource.Name    = name;
                resource.Content = File.ReadAllBytes(FindFile(name));
                resource.Type    = new CiArrayStorageType {
                    ElementType = CiByteType.Value, Length = resource.Content.Length
                };
                this.BinaryResources.Add(name, resource);
            }
            expr.Resource = resource;
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiNewExpr expr)
        {
            CiType             type             = expr.NewType;
            CiClassStorageType classStorageType = type as CiClassStorageType;

            if (classStorageType != null)
            {
                classStorageType.Class             = ResolveClass(classStorageType.Class);
                classStorageType.Class.IsAllocated = true;
            }
            else
            {
                CiArrayStorageType arrayStorageType = (CiArrayStorageType)type;
                arrayStorageType.ElementType = Resolve(arrayStorageType.ElementType);
                arrayStorageType.LengthExpr  = Coerce(Resolve(arrayStorageType.LengthExpr), CiIntType.Value);
            }
            return(expr);
        }

        CiExpr Resolve(CiExpr expr)
        {
            return(expr.Accept(this));
        }

        void ICiSymbolVisitor.Visit(CiField field)
        {
            field.Type = Resolve(field.Type);
        }

        bool Resolve(ICiStatement[] statements)
        {
            bool reachable = true;

            foreach (ICiStatement child in statements)
            {
                if (!reachable)
                {
                    throw new ResolveException("Unreachable statement");
                }
                child.Accept(this);
                reachable = child.CompletesNormally;
            }
            return(reachable);
        }

        void ICiStatementVisitor.Visit(CiBlock statement)
        {
            statement.CompletesNormally = Resolve(statement.Statements);
        }

        void ICiStatementVisitor.Visit(CiConst statement)
        {
        }

        void ICiStatementVisitor.Visit(CiVar statement)
        {
            statement.Type = Resolve(statement.Type);
            if (statement.InitialValue != null)
            {
                CiType type         = statement.Type;
                CiExpr initialValue = Resolve(statement.InitialValue);
                CheckCopyPtr(type, initialValue);
                if (type is CiArrayStorageType)
                {
                    type = ((CiArrayStorageType)type).ElementType;
                    CiConstExpr ce = Coerce(initialValue, type) as CiConstExpr;
                    if (ce == null)
                    {
                        throw new ResolveException("Array initializer is not constant");
                    }
                    statement.InitialValue = ce;
                    if (type == CiBoolType.Value)
                    {
                        if (!false.Equals(ce.Value))
                        {
                            throw new ResolveException("Bool arrays can only be initialized with false");
                        }
                    }
                    else if (type == CiByteType.Value)
                    {
                        if (!((byte)0).Equals(ce.Value))
                        {
                            throw new ResolveException("Byte arrays can only be initialized with zero");
                        }
                    }
                    else if (type == CiIntType.Value)
                    {
                        if (!0.Equals(ce.Value))
                        {
                            throw new ResolveException("Int arrays can only be initialized with zero");
                        }
                    }
                    else
                    {
                        throw new ResolveException("Invalid array initializer");
                    }
                }
                else
                {
                    statement.InitialValue = Coerce(initialValue, type);
                }
            }
        }

        void ICiStatementVisitor.Visit(CiExpr statement)
        {
            Resolve((CiExpr)statement);
        }

        void ICiStatementVisitor.Visit(CiAssign statement)
        {
            statement.Target = ResolveLValue(statement.Target);
            if (statement.Target is CiVarAccess && ((CiVarAccess)statement.Target).Var == this.CurrentMethod.This)
            {
                throw new ResolveException("Cannot assign to this");
            }
            CiMaybeAssign source = statement.Source;

            if (source is CiAssign)
            {
                Resolve((ICiStatement)source);
            }
            else
            {
                source = Resolve((CiExpr)source);
            }
            CiType type = statement.Target.Type;

            CheckCopyPtr(type, source);
            statement.Source = Coerce(source, type);
            if (statement.Op != CiToken.Assign && type != CiIntType.Value && type != CiByteType.Value)
            {
                if (statement.Op == CiToken.AddAssign && type is CiStringStorageType && statement.Source.Type is CiStringType)
                {
                }                  // OK
                else
                {
                    throw new ResolveException("Invalid compound assignment");
                }
            }
        }

        void ICiStatementVisitor.Visit(CiDelete statement)
        {
            statement.Expr = Resolve(statement.Expr);
            ICiPtrType type = statement.Expr.Type as ICiPtrType;

            if (type == null)
            {
                throw new ResolveException("'delete' takes a class or array pointer");
            }
            if (statement.Expr.HasSideEffect)
            {
                throw new ResolveException("Side effects not allowed in 'delete'");
            }
            this.WritablePtrTypes.Add(type);
        }

        void ICiStatementVisitor.Visit(CiBreak statement)
        {
            if (this.CurrentLoopOrSwitch == null)
            {
                throw new ResolveException("break outside loop and switch");
            }
            this.CurrentLoopOrSwitch.CompletesNormally = true;
        }

        void ICiStatementVisitor.Visit(CiContinue statement)
        {
            if (this.CurrentLoop == null)
            {
                throw new ResolveException("continue outside loop");
            }
        }

        void ResolveLoop(CiLoop statement)
        {
            statement.CompletesNormally = false;
            if (statement.Cond != null)
            {
                statement.Cond = Coerce(Resolve(statement.Cond), CiBoolType.Value);
                statement.CompletesNormally = !statement.Cond.IsConst(false);
            }
            CiLoop oldLoop = this.CurrentLoop;
            CiCondCompletionStatement oldLoopOrSwitch = this.CurrentLoopOrSwitch;

            this.CurrentLoopOrSwitch = this.CurrentLoop = statement;
            Resolve(statement.Body);
            this.CurrentLoop         = oldLoop;
            this.CurrentLoopOrSwitch = oldLoopOrSwitch;
        }

        void ICiStatementVisitor.Visit(CiDoWhile statement)
        {
            ResolveLoop(statement);
        }

        void ICiStatementVisitor.Visit(CiFor statement)
        {
            if (statement.Init != null)
            {
                Resolve(statement.Init);
            }
            if (statement.Advance != null)
            {
                Resolve(statement.Advance);
            }
            ResolveLoop(statement);
        }

        void ICiStatementVisitor.Visit(CiIf statement)
        {
            statement.Cond = Coerce(Resolve(statement.Cond), CiBoolType.Value);
            Resolve(statement.OnTrue);
            if (statement.OnFalse != null)
            {
                Resolve(statement.OnFalse);
                statement.CompletesNormally = statement.OnTrue.CompletesNormally || statement.OnFalse.CompletesNormally;
            }
            else
            {
                statement.CompletesNormally = true;
            }
        }

        void ICiStatementVisitor.Visit(CiNativeBlock statement)
        {
        }

        void ICiStatementVisitor.Visit(CiReturn statement)
        {
            CiType type = this.CurrentMethod.Signature.ReturnType;

            if (type != CiType.Void)
            {
                statement.Value = Coerce(Resolve(statement.Value), type);
            }
        }

        void ICiStatementVisitor.Visit(CiSwitch statement)
        {
            statement.Value = Resolve(statement.Value);
            CiType type = statement.Value.Type;
            CiCondCompletionStatement oldLoopOrSwitch = this.CurrentLoopOrSwitch;

            this.CurrentLoopOrSwitch = statement;

            HashSet <object> values          = new HashSet <object>();
            CiCase           fallthroughFrom = null;

            foreach (CiCase kase in statement.Cases)
            {
                for (int i = 0; i < kase.Values.Length; i++)
                {
                    kase.Values[i] = ResolveConstExpr((CiExpr)kase.Values[i], type);
                    if (!values.Add(kase.Values[i]))
                    {
                        throw new ResolveException("Duplicate case value");
                    }
                }
                if (fallthroughFrom != null)
                {
                    if (fallthroughFrom.FallthroughTo == null)
                    {
                        throw new ResolveException("goto default followed by case");
                    }
                    if (!ResolveConstExpr(fallthroughFrom.FallthroughTo, type).Equals(kase.Values[0]))
                    {
                        throw new ResolveException("goto case doesn't match the next case");
                    }
                }
                bool reachable = Resolve(kase.Body);
                if (kase.Fallthrough)
                {
                    if (!reachable)
                    {
                        throw new ResolveException("goto is not reachable");
                    }
                    fallthroughFrom = kase;
                }
                else
                {
                    if (reachable)
                    {
                        throw new ResolveException("case must end with break, return, throw or goto");
                    }
                    fallthroughFrom = null;
                }
            }

            if (statement.DefaultBody != null)
            {
                if (fallthroughFrom != null && fallthroughFrom.FallthroughTo != null)
                {
                    throw new ResolveException("goto case followed by default");
                }
                bool reachable = Resolve(statement.DefaultBody);
                if (reachable)
                {
                    throw new ResolveException("default must end with break, return, throw or goto");
                }
            }
            else
            {
                if (fallthroughFrom != null)
                {
                    throw new ResolveException("goto cannot be the last statement in switch");
                }
            }

            this.CurrentLoopOrSwitch = oldLoopOrSwitch;
        }

        void ICiStatementVisitor.Visit(CiThrow statement)
        {
            statement.Message = Coerce(Resolve(statement.Message), CiStringPtrType.Value);
            this.ThrowingMethods.Add(this.CurrentMethod);
        }

        void ICiStatementVisitor.Visit(CiWhile statement)
        {
            ResolveLoop(statement);
        }

        void Resolve(ICiStatement statement)
        {
            statement.Accept(this);
        }

        void ICiSymbolVisitor.Visit(CiMethod method)
        {
            this.CurrentMethod = method;
            Resolve(method.Signature);
            if (method.CallType != CiCallType.Abstract)
            {
                Resolve(method.Body);
                if (method.Signature.ReturnType != CiType.Void && method.Body.CompletesNormally)
                {
                    throw new ResolveException("Method can complete without a return value");
                }
            }
            this.CurrentMethod = null;
        }

        void ResolveBase(CiClass klass)
        {
            if (klass.BaseClass != null)
            {
                klass.BaseClass      = ResolveClass(klass.BaseClass);
                klass.Members.Parent = klass.BaseClass.Members;
            }
        }

        void ICiSymbolVisitor.Visit(CiClass klass)
        {
            this.CurrentClass = klass;
            this.Symbols      = klass.Members;
            if (klass.Constructor != null)
            {
                klass.Constructor.Accept(this);
            }
            foreach (CiSymbol member in klass.Members)
            {
                member.Accept(this);
            }
            klass.BinaryResources = this.BinaryResources.Values.ToArray();
            this.BinaryResources.Clear();
            this.Symbols      = this.Symbols.Parent;
            this.CurrentClass = null;
        }
Beispiel #3
0
 CiMaybeAssign Coerce(CiMaybeAssign expr, CiType expected)
 {
     CiType got = expr.Type;
     if (expected.Equals(got))
     return expr;
     if (expected == CiIntType.Value && got == CiByteType.Value) {
     CiConstExpr konst = expr as CiConstExpr;
     if (konst != null)
         return new CiConstExpr((object) (int) (byte) konst.Value);
     CiCondExpr cond = expr as CiCondExpr;
     if (cond != null && (cond.OnTrue is CiConstExpr || cond.OnFalse is CiConstExpr)) {
         // avoid ((foo ? 1 : 0) & 0xff) in Java
         return Coerce(cond, expected);
     }
     if (expr is CiArrayAccess) {
         CiConstAccess ca = ((CiArrayAccess) expr).Array as CiConstAccess;
         if (ca != null && ca.Const.Is7Bit)
             return expr;
     }
     return new CiCoercion { ResultType = expected, Inner = expr };
     }
     if (expected == CiByteType.Value && got == CiIntType.Value) {
     CiConstExpr konst = expr as CiConstExpr;
     if (konst != null)
         return new CiConstExpr((object) (byte) (int) konst.Value);
     return new CiCoercion { ResultType = expected, Inner = expr };
     }
     if (expected == CiStringPtrType.Value && (got == CiType.Null || got is CiStringType))
     return expr;
     if (expected is CiStringStorageType && got is CiStringType)
     return expr;
     if (expected is CiClassType) {
     if (got == CiType.Null)
         return expr;
     if (Extends(got, ((CiClassType) expected).Class)) {
         if (expr is CiCondExpr) {
             // C doesn't like &(cond ? foo : bar)
             return Coerce((CiCondExpr) expr, expected);
         }
         return new CiCoercion { ResultType = expected, Inner = expr };
     }
     }
     if (expected is CiArrayPtrType) {
     if (got == CiType.Null)
         return expr;
     CiArrayType gotArray = got as CiArrayType;
     if (got != null && ((CiArrayPtrType) expected).ElementType.Equals(gotArray.ElementType))
         return new CiCoercion { ResultType = expected, Inner = expr };
     }
     throw new ResolveException("Expected {0}, got {1}", expected, got);
 }