public override AstNode Visit(BinaryAssignOperation node) { // Begin the node. builder.BeginNode(node); // Get the expressions. Expression left = node.GetVariable(); Expression right = node.GetValue(); // Get the types. IChelaType leftType = left.GetNodeType(); IChelaType rightType = right.GetNodeType(); IChelaType coercionType = node.GetCoercionType(); IChelaType secondCoercion = node.GetSecondCoercion(); // Get the variable. Variable variable = (Variable)left.GetNodeValue(); left.Accept(this); // Duplicate the variable reference. DuplicateReference(node, variable); // If the variable is an event, if(variable.IsEvent()) { // Use event functions. EventVariable eventVar = (EventVariable)variable; // Send the argument. right.Accept(this); Cast(node, right.GetNodeValue(), rightType, secondCoercion); // Select the correct function. Function modifier = null; if(node.GetOperation() == BinaryOperation.OpAdd) modifier = eventVar.AddModifier; else modifier = eventVar.RemoveModifier; // Invoke the modifier. if(!modifier.IsStatic()) { Method method = (Method)modifier; if(method.IsVirtual()) builder.CreateCallVirtual(method, 2); else builder.CreateCall(method, 2); } else { builder.CreateCall(modifier, 1); } // Return the node. return builder.EndNode(); } // Duplicate again. DuplicateReference(node, variable); // Read the variable. Cast(node, variable, leftType, coercionType); // Send the right operand. right.Accept(this); if(rightType != secondCoercion) Cast(node, right.GetNodeValue(), rightType, secondCoercion); // Get the overloaded operator. Function op = node.GetOverload(); // Perform the operation if(op != null) { // Use the overloaded operation. builder.CreateCall(op, 2); // Coerce the result. IChelaType opResult = op.GetFunctionType().GetReturnType(); if(opResult != coercionType) builder.CreateCast(coercionType); } else { switch(node.GetOperation()) { case BinaryOperation.OpAdd: builder.CreateAdd(); break; case BinaryOperation.OpSub: builder.CreateSub(); break; case BinaryOperation.OpMul: builder.CreateMul(); break; case BinaryOperation.OpDiv: builder.CreateDiv(); break; case BinaryOperation.OpMod: builder.CreateMod(); break; case BinaryOperation.OpBitAnd: builder.CreateAnd(); break; case BinaryOperation.OpBitOr: builder.CreateOr(); break; case BinaryOperation.OpBitXor: builder.CreateXor(); break; case BinaryOperation.OpBitLeft: builder.CreateShLeft(); break; case BinaryOperation.OpBitRight: builder.CreateShRight(); 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: // Shouldn't reach here. break; } } // Now, perform the assignment. PerformAssignment(node, variable); // Set the node value. node.SetNodeValue(variable); return builder.EndNode(); }
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; }