Exemple #1
0
        public override AstNode Visit(BinaryAssignOperation node)
        {
            // Get the expressions.
            Expression left = node.GetVariable();
            Expression right = node.GetValue();

            // Visit the expressions.
            left.Accept(this);
            right.Accept(this);

            // Check the types.
            IChelaType leftType = left.GetNodeType();
            IChelaType rightType = right.GetNodeType();

            // The variable must be a reference.
            if(!leftType.IsReference())
                Error(node, "trying to set something that isn't a reference.");
            leftType = DeReferenceType(leftType);

            // Don't modify constants.
            if(leftType.IsConstant())
                Error(node, "cannot modify constants.");

            // Check coercion.
            // TODO: Add operator overloading.

            // Set the variable type.
            node.SetNodeType(left.GetNodeType());

            // Check for pointer arithmetic.
            if(leftType.IsPointer())
            {
                // Only addition and subtraction are accepted.
                int op = node.GetOperation();
                if(op != BinaryOperation.OpAdd && op != BinaryOperation.OpSub)
                    Error(node, "only addition and subtraction of pointers is supported.");

                // Make sure the right type is an integer or another pointer.
                if(rightType.IsReference())
                    rightType = DeReferenceType(rightType);

                // De-const the right operand.
                if(rightType.IsConstant())
                    rightType = DeConstType(rightType);

                // Don't allow right operand pointer.
                if(!rightType.IsInteger())
                    Error(node, "right operand must be integer.");

                // Set the coercion type and pointer arithmetic flags.
                node.SetCoercionType(leftType);
                node.SetSecondCoercion(rightType);
                node.SetPointerArithmetic(true);

                return node;
            }
            else if(leftType.IsReference())
            {
                // Handle the event subscription.
                leftType = DeReferenceType(leftType);

                if(!leftType.IsClass())
                    Error(node, "unsupported operation.");

                // Make sure its actually a delegate.
                Class delegateClass = currentModule.GetDelegateClass();
                Class delegateType = (Class)leftType;
                if(!delegateType.IsDerivedFrom(delegateClass))
                    Error(node, "cannot subscribe no delegates.");

                // Check the operation.
                int op = node.GetOperation();
                if(op != BinaryOperation.OpAdd && op != BinaryOperation.OpSub)
                    Error(node, "invalid event subscription/delegate operation.");

                // Perform coercion.
                leftType = ReferenceType.Create(delegateType);
                if(Coerce(node, leftType, rightType, right.GetNodeValue()) != leftType)
                    Error(node, "unexistent implicit cast for assignment.");

                // Get the overload operator.
                Variable variable = (Variable)left.GetNodeValue();
                if(!variable.IsEvent())
                {
                    string opName = op == BinaryOperation.OpAdd ? "Combine" : "Remove";

                    // Find the first no static function with 2 arguments.
                    FunctionGroup opGroup = (FunctionGroup)delegateClass.FindMember(opName);
                    Function overload = null;
                    foreach(FunctionGroupName gname in opGroup.GetFunctions())
                    {
                        // Ignore no static functions.
                        if(!gname.IsStatic())
                            continue;

                        // Select the first function with 2 arguments.
                        if(gname.GetFunctionType().GetArgumentCount() == 2)
                        {
                            overload = gname.GetFunction();
                            break;
                        }
                    }

                    // Make sure the function was found.
                    if(overload == null)
                        Error(node, "Runtime delegate doesn't have function " + opName);

                    // Use the overload.
                    node.SetOverload(overload);
                }

                node.SetCoercionType(leftType);
                node.SetSecondCoercion(leftType);
                return node;
            }

            if(Coerce(node, leftType, rightType, right.GetNodeValue()) != leftType)
                Error(node, "unexistent implicit cast for assignment.");
            node.SetCoercionType(leftType);
            node.SetSecondCoercion(leftType);

            // Perform validation
            switch(node.GetOperation())
            {
            case BinaryOperation.OpAdd:
            case BinaryOperation.OpSub:
            case BinaryOperation.OpMul:
            case BinaryOperation.OpDiv:
            case BinaryOperation.OpMod:
                if(leftType == ChelaType.GetBoolType())
                    Error(node, "Arithmetic operations aren't available with boolean values.");
                break;
            case BinaryOperation.OpBitAnd:
            case BinaryOperation.OpBitOr:
            case BinaryOperation.OpBitXor:
            case BinaryOperation.OpBitLeft:
            case BinaryOperation.OpBitRight:
                if(leftType.IsFloatingPoint() || leftType == ChelaType.GetBoolType())
                    Error(node, "Bitwise operations aren't available with floating point and boolean values.");
                break;
            case BinaryOperation.OpLT:
            case BinaryOperation.OpGT:
            case BinaryOperation.OpEQ:
            case BinaryOperation.OpNEQ:
            case BinaryOperation.OpLEQ:
            case BinaryOperation.OpGEQ:
            case BinaryOperation.OpLAnd:
            case BinaryOperation.OpLOr:
                Error(node, "Operation without assignment version.");
                break;
            default:
                Error(node, "Compiler bug, unknown binary operation.");
                break;
            }

            // Check for the read-only constraint.
            Variable variableSlot = left.GetNodeValue() as Variable;
            if(variableSlot != null && variableSlot.IsReadOnly())
                CheckReadOnlyConstraint(node, variableSlot);

            return node;
        }