2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Microsoft.VisualBasic / Microsoft.VisualBasic / Microsoft.VisualBasic.CompilerServices / FlowControl.cs
index b4ca1f496873d61787a0fe01fd41e80a426ffe84..0e6ac6b45ee5c09263dbe2529af431a518350b4d 100644 (file)
-//\r
-// FlowControl.cs\r
-//\r
-// Author:\r
-//   Chris J Breisch (cjbreisch@altavista.net)\r
-//\r
-// (C) 2002 Chris J Breisch\r
-//\r
-namespace Microsoft.VisualBasic.CompilerServices {\r
-       [Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute] \r
-       [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] \r
-       [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Auto)] \r
-       sealed public class FlowControl {\r
-               // Declarations\r
-               // Constructors\r
-               // Properties\r
-               // Methods\r
-               public static System.Boolean ForNextCheckR4 (System.Single count, System.Single limit, System.Single StepValue) { return false;}\r
-               public static System.Boolean ForNextCheckR8 (System.Double count, System.Double limit, System.Double StepValue) { return false;}\r
-               public static System.Boolean ForNextCheckDec (System.Decimal count, System.Decimal limit, System.Decimal StepValue) { return false;}\r
-               public static System.Boolean ForLoopInitObj (System.Object Counter, System.Object Start, System.Object Limit, System.Object StepValue, ref System.Object LoopForResult, ref System.Object CounterResult) { return false;}\r
-               public static System.Boolean ForNextCheckObj (System.Object Counter, System.Object LoopObj, ref System.Object CounterResult) { return false;}\r
-               public static System.Collections.IEnumerator ForEachInArr (System.Array ary) { return null;}\r
-               public static System.Collections.IEnumerator ForEachInObj (System.Object obj) { return null;}\r
-               public static System.Boolean ForEachNextObj (ref System.Object obj, ref System.Collections.IEnumerator enumerator) { return false;}\r
-               public static void CheckForSyncLockOnValueType (System.Object obj) { }\r
-               // Events\r
-       };\r
-}\r
+ //
+// FlowControl.cs
+//
+// Author:
+//   Chris J Breisch (cjbreisch@altavista.net) 
+//   Dennis Hayes (dennish@raytek.com)
+//
+// (C) 2002 Chris J Breisch
+//
+/*
+  * Copyright (c) 2002-2003 Mainsoft Corporation.
+  * Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the "Software"),
+  * to deal in the Software without restriction, including without limitation
+  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  * and/or sell copies of the Software, and to permit persons to whom the
+  * Software is furnished to do so, subject to the following conditions:
+  * 
+  * The above copyright notice and this permission notice shall be included in
+  * all copies or substantial portions of the Software.
+  * 
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  * DEALINGS IN THE SOFTWARE.
+  */
+/**
+ * This class allows to execute loop statement of VisualBasic .NET
+ */
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+
+namespace Microsoft.VisualBasic.CompilerServices 
+{
+       [StandardModule, EditorBrowsable(EditorBrowsableState.Never)] 
+       sealed public class FlowControl {
+               private FlowControl () {}
+
+               private sealed /*static (final)in mainsoft java code*/ class ObjectFor {
+                       public object Counter;
+
+                       public object Limit;
+
+                       public object StepValue;
+
+                       public bool PositiveStep;
+
+                       public Type EnumType;
+               }
+    
+               /**
+                * This method check if the loop can continued.
+                * if the StepValue is positive it check that count is smaller than the limit.
+                * if the StepValue is negative it check that count is bigger than the limit. 
+                * @param count
+                * @param limit
+                * @param StepValue
+                * @return boolean True of the for next loop can continue and false otherwise.
+                */
+               public static bool ForNextCheckR4(float count, float limit, float StepValue) {
+                       bool positiveStep = StepValue > 0.0F;
+                       bool isCountSmallThenLimit = count <= limit;
+                       return positiveStep? isCountSmallThenLimit : !isCountSmallThenLimit;
+               }
+    
+               /**
+                * This method check if the loop can continued.
+                * if the StepValue is positive it check that count is smaller than the limit.
+                * if the StepValue is negative it check that count is bigger than the limit. 
+                * @param count
+                * @param limit
+                * @param StepValue
+                * @return boolean True of the for next loop can continue and false otherwise.
+                */
+               public static bool ForNextCheckR8(double count, double limit, double StepValue) {
+                       bool positiveStep = StepValue > 0.0;
+                       bool isCountSmallThenLimit = count <= limit;
+                       return positiveStep? isCountSmallThenLimit : !isCountSmallThenLimit;
+               }
+
+               /**
+                * This method check if the loop can continued.
+                * if the StepValue is positive it check that count is smaller than the limit.
+                * if the StepValue is negative it check that count is bigger than the limit. 
+                * @param count
+                * @param limit
+                * @param StepValue
+                * @return boolean True of the for next loop can continue and false otherwise.
+                */
+               public static bool ForNextCheckDec(Decimal count, Decimal limit, Decimal StepValue) {
+                       bool positiveStep = StepValue.CompareTo(Decimal.Zero) < 0;
+                       bool isCountSmallThenLimit = count.CompareTo(limit) >= 0;
+                       return positiveStep? isCountSmallThenLimit : !isCountSmallThenLimit; 
+               }
+    
+               /**
+                * This method method updates the LoopFor reference and the Counter reference
+                * object according to the given params and returns if this loop can continue. 
+                * @param Counter this loop counter value
+                * @param Start this loop start value 
+                * @param Limit this loop limitation value
+                * @param StepValue this loop step value
+                * @param lfr the LoopFor reference object
+                * @param cr the Counter object reference 
+                * @return boolean is the returned LoopFor object can continue.
+                */
+               public static bool ForLoopInitObj(
+                       object Counter,
+                       object Start,
+                       object Limit,
+                       object StepValue,
+                       ref System.Object lfr,
+                       ref System.Object cr) {
+
+                       object CounterResult = cr;
+
+                       if (Start == null) {
+                               throw new ArgumentException("Argument_InvalidNullValue1 " + " Start");
+                       }
+                       if (Limit == null) {
+                               throw new ArgumentException("Argument_InvalidNullValue1 " + " Limit");
+                       }
+                       if (StepValue == null) {
+                               throw new ArgumentException("Argument_InvalidNullValue1 " + " Step");
+                       }
+                       //gets the type of all the given parameters
+                       Type startType = Start.GetType();
+                       Type limitType = Limit.GetType();
+                       Type stepType = StepValue.GetType();
+
+                       //gets the widest common type code
+               
+                       TypeCode commonTypeCode = ObjectType.GetWidestType(Start, Limit, false);
+                       commonTypeCode = ObjectType.GetWidestType(StepValue, commonTypeCode);
+                       if (commonTypeCode == TypeCode.String) {
+                               commonTypeCode = TypeCode.Double;
+                       }
+                       if (commonTypeCode == TypeCode.Object) {
+                               //TODO:
+                               //throw new ArgumentException(
+                               //      Utils.GetResourceString(
+                               //      "ForLoop_CommonType3",
+                               //      Utils.VBFriendlyName(startType),
+                               //      Utils.VBFriendlyName(limitType),
+                               //      Utils.VBFriendlyName(StepValue)));
+                               throw new ArgumentException("ForLoop_CommonType3 startType limitType StepValue");
+                       }
+
+                       ObjectFor objectFor = new ObjectFor();
+                       TypeCode startTypeCode = Type.GetTypeCode(startType);
+                       TypeCode limitTypeCode = Type.GetTypeCode(limitType);
+                       TypeCode stepTypeCode = Type.GetTypeCode(stepType);
+                       Type enumType = null;
+
+                       bool isStartTypeValidEnum =  (startTypeCode == commonTypeCode) && (startType.IsEnum);
+                       bool isLimitTypeValidEnum =  (limitTypeCode == commonTypeCode) && (limitType.IsEnum);
+                       bool isStepTypeValidEnum =  (stepTypeCode == commonTypeCode) && (stepType.IsEnum);
+        
+                       bool isStartAndStepTypeEqual = (startType == stepType);
+                       bool isStartAndLimitTypeEqual = (startType == limitType);
+                       bool isStepAndLimitTypeEqual = (stepType == limitType);
+
+                       //the For loop has enum type in the following case
+                       //1. step is enum and it's type code equal to commonTypeCode and start and 
+                       //  limit don't meet this condition.
+                       //2. step and start are enum and their type code equal to commonTypeCode and
+                       //  their types are equal. limit doesn't meet this condition about been enum
+                       //  or about been equal to commonTypeCode.
+                       //3. step and limit are enum and their type code equal to commonTypeCode and
+                       //  their types are equal. start doesn't meet this condition about been enum
+                       //  or about been equal to commonTypeCode.
+                       //4. step and limit and start are enum and their type code equal to commonTypeCode and
+                       //  their types are equal.
+                       //5. start is enum and it's type code equal to commonTypeCode .step and 
+                       //  limit don't meet this condition.
+                       //6. limit is enum and it's type code equal to commonTypeCode .step and 
+                       //  start don't meet this condition.
+                       //7.start and limit are enum and their type code equal to commonTypeCode and
+                       //  their types are equal. step doesn't meet this condition about been enum
+                       //  or about been equal to commonTypeCode.
+                       //
+        
+                       if (isStartTypeValidEnum && isLimitTypeValidEnum && isStepTypeValidEnum
+                               &&  isStartAndStepTypeEqual && isStartAndLimitTypeEqual)
+                               enumType = startType;
+                       else if (isStartTypeValidEnum && isStepTypeValidEnum && isStartAndStepTypeEqual)
+                               enumType = startType;
+                       else if (isStartTypeValidEnum && isStepTypeValidEnum && isStartAndStepTypeEqual)
+                               enumType = startType;
+                       else if (isStartTypeValidEnum && isLimitTypeValidEnum && isStartAndLimitTypeEqual)
+                               enumType = startType;
+                       else if (isStartTypeValidEnum && !isLimitTypeValidEnum && !isStepTypeValidEnum)
+                               enumType = startType;
+                       else if (!isStartTypeValidEnum && isLimitTypeValidEnum && !isStepTypeValidEnum)
+                               enumType = limitType; 
+                       else if (!isStartTypeValidEnum && !isLimitTypeValidEnum && isStepTypeValidEnum)
+                               enumType = stepType;            
+        
+                       objectFor.EnumType = enumType;
+        
+                       //set the counter field of objectFor with Start value transleted to 
+                       // the widest common type code
+                       objectFor.Counter = convertType(Start, commonTypeCode,"Start");
+                       //set the Limit field of objectFor with Limit value transleted to 
+                       // the widest common type code
+                       objectFor.Limit = convertType(Limit, commonTypeCode,"Limit");
+                       //set the StepValue field of objectFor with StepValue value transleted to 
+                       // the widest common type code
+                       objectFor.StepValue = convertType(StepValue, commonTypeCode,"Step");
+                       //local is the value of zero in the widest common type code
+
+                       object local = ObjectType.CTypeHelper(0, commonTypeCode);
+        
+                       IComparable iComparable = (IComparable)objectFor.StepValue;
+                       objectFor.PositiveStep = iComparable.CompareTo(local) >= 0;
+
+                       // sets the loop for reference 
+                       lfr = objectFor;
+        
+                       //sets the counter reference
+                       if (objectFor.EnumType != null) {
+                               cr = Enum.ToObject(objectFor.EnumType, objectFor.Counter);
+                       }
+                       else {
+                               cr = objectFor.Counter;
+                       }        
+                       return CheckContinueLoop(objectFor);
+               }
+    
+               private static object convertType(object original, TypeCode typeCode, string fieldName) {
+                       try {
+                               return ObjectType.CTypeHelper(original, typeCode);
+                       }
+                       catch /*(Exception e)*/ {
+                               throw new ArgumentException("ForLoop_ConvertToType3 " + fieldName);
+                       }
+               }
+
+               public static bool ForNextCheckObj(object Counter, object LoopObj,
+                       ref System.Object CounterResult) {// throws java.lang.Exception
+                       TypeCode generalTypeCode = 0;
+
+                       if (LoopObj == null) {
+                               //TODO: use resource for the correct execption.
+                               throw new Exception("VB error message #92 ForNextCheckObj LoopObj cannot be null");
+                               //throw ExceptionUtils.VbMakeException(92);//correct java version
+                       }
+                       if (Counter == null) {
+                               throw new NullReferenceException("Argument_InvalidNullValue1 " + " Counter");
+                               //TODO:
+                               //throw new NullReferenceException(
+                               //    Utils.GetResourceString(
+                               //        "Argument_InvalidNullValue1",
+                               //        "Counter"));
+                       }
+                        ObjectFor objectFor = (ObjectFor) LoopObj;
+
+                       IConvertible iConvertible_counter = (IConvertible)Counter;
+                       IConvertible iConvertible_step = (IConvertible) objectFor.StepValue;
+
+                       TypeCode counterTypeCode = iConvertible_counter.GetTypeCode();
+                       TypeCode stepTypeCode = iConvertible_step.GetTypeCode();
+                       
+                       if (counterTypeCode == stepTypeCode && counterTypeCode != TypeCode.String) {
+                               generalTypeCode = counterTypeCode;
+                       }
+                       else {
+                               generalTypeCode = ObjectType.GetWidestType(counterTypeCode, stepTypeCode);
+                               if (generalTypeCode == TypeCode.String) {
+                                       generalTypeCode = TypeCode.Double;
+                               }
+                               Counter = convertType(Counter, generalTypeCode,"Start");
+                               objectFor.Limit = convertType(objectFor.Limit, generalTypeCode,"Limit");
+                               objectFor.StepValue = convertType(objectFor.StepValue, generalTypeCode,"Step");
+                       }
+                       //changes the counter field to be the sum of step and counter 
+                       objectFor.Counter = ObjectType.AddObj(Counter, objectFor.StepValue);
+                       IConvertible iConvertible_objectCounter = (IConvertible)objectFor.Counter;
+                       TypeCode objectCounterTypeCode = iConvertible_objectCounter.GetTypeCode();
+
+                       //setting the counter in counter reference.
+                       //if the for is enum type change counter to enum. 
+                       if (objectFor.EnumType != null) {
+                               CounterResult = Enum.ToObject(objectFor.EnumType, objectFor.Counter);
+                       }
+                       else {
+                               CounterResult = objectFor.Counter;
+                       }
+        
+                       //if the counter after the change didn't change it's type return true if 
+                       // the for  object can continue loop and false otherwise.
+                       //if the counter changed it's type change all for object fields to counter
+                       //current type and return false. 
+                       if (objectCounterTypeCode == generalTypeCode) {
+                               return CheckContinueLoop(objectFor);
+                       }
+                       else {
+                               objectFor.Limit = ObjectType.CTypeHelper(objectFor.Limit, objectCounterTypeCode);
+        
+                               objectFor.StepValue =
+                                       ObjectType.CTypeHelper(objectFor.StepValue, objectCounterTypeCode);
+                               return false;
+                       }
+               }
+    
+               /**
+                * This method returns IEnumertator for a given array
+                * @param ary the given array
+                * @return IEnumerator the array's Enumerator
+                */
+               public static IEnumerator ForEachInArr(Array ary) {// throws java.lang.Exception
+                       IEnumerator iEnumerator = (IEnumerator)ary;//is ArrayStaticWrapper.GetEnumerator(ary); in java code.
+                       if (iEnumerator != null)
+                               return iEnumerator;
+                       throw ExceptionUtils.VbMakeException(92);
+               }
+    
+               /**
+                * This method gets IEnumerator for a given object that implements IEnumerable
+                * @param obj the object that implements IEnumerable
+                * @return IEnumerator the object's IEnumerator.
+                */
+               public static IEnumerator ForEachInObj(object obj) {// throws java.lang.Exception
+                       if (obj == null)
+                               throw ExceptionUtils.VbMakeException(91);
+
+                       IEnumerable iEnumerable = (IEnumerable)obj;
+                       if (iEnumerable != null) {
+                               IEnumerator iEnumerator = iEnumerable.GetEnumerator();
+                               if (iEnumerator != null)
+                                       return iEnumerator;
+                       }
+                       string s = obj.GetType().ToString();
+                       ExceptionUtils.ThrowException1(100, s);
+                       return null;
+               }
+    
+               /**
+                * This method set the next value of teh Enumerator in the reference.
+                * if there isn't next value , null is been set in the referece. 
+                * @param obj
+                * @param enumerator
+                * @return boolean returns the value of enumerator.MoveNext().
+                */
+               public static bool ForEachNextObj(ref System.Object obj, IEnumerator enumerator) {
+                       if (enumerator.MoveNext()) {
+                               obj = enumerator.Current;
+                               return true;
+                       }
+                       obj = null;
+                       return false;
+               }
+    
+               /**
+                * This method check if the loop can continued.
+                * if the step is positive it check that the counter is smaller than the limit.
+                * if the step is negative it check that the counter is bigger than the limit. 
+                * @param LoopFor
+                * @return boolean
+                */
+               private static bool CheckContinueLoop(ObjectFor LoopFor) {
+                       //TODO:
+                       //throw new NotImplementedException("MSVB.Compilerservices.flowcontrol needs help");
+                       IComparable iComparable = (IComparable)LoopFor.Counter;
+                       
+                       if (iComparable != null) {
+                               int i = iComparable.CompareTo(LoopFor.Limit);
+                               bool isCountSmallThenLimit = i<=0;
+                               return LoopFor.PositiveStep ? isCountSmallThenLimit : !isCountSmallThenLimit;
+                       }
+                       throw new ArgumentException("Argument_IComparable2 loop control variable"); // + Utils.VBFriendlyName(LoopFor.Counter)));
+                               //TODO: verify this and the above are the same and remove.
+                               //throw new ArgumentException(Utils.GetResourceString(
+                               //      "Argument_IComparable2", "loop control variable",
+                               //      Utils.VBFriendlyName(LoopFor.Counter)));
+                       }
+    
+               /**
+                * This method throws exception if the input is Valuetype  
+                * @param obj the object that need to be checked
+                */
+               public static void CheckForSyncLockOnValueType(object obj) {
+                       //TODO:
+                       //throw new NotImplementedException("MSVB.Compilerservices.flowcontrol needs help");
+                       if (obj != null && obj.GetType().IsValueType)
+                               throw new ArgumentException(Utils.GetResourceString("SyncLockRequiresReferenceType1 "));
+                       //TODO: verify this and the above are the same and remove.
+                       //if (obj != null && ObjectStaticWrapper.GetType(obj).get_IsValueType())
+                       //      throw new ArgumentException(Utils.GetResourceString(
+                       //              "SyncLockRequiresReferenceType1",Utils.VBFriendlyName(obj)));
+               }
+       }
+}