This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / Microsoft.VisualBasic / Microsoft.VisualBasic / Microsoft.VisualBasic.CompilerServices / FlowControl.cs
1  //
2 // FlowControl.cs
3 //
4 // Author:
5 //   Chris J Breisch (cjbreisch@altavista.net) 
6 //   Dennis Hayes (dennish@raytek.com)
7 //
8 // (C) 2002 Chris J Breisch
9 //
10 /*
11   * Copyright (c) 2002-2003 Mainsoft Corporation.
12   * Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13   *
14   * Permission is hereby granted, free of charge, to any person obtaining a
15   * copy of this software and associated documentation files (the "Software"),
16   * to deal in the Software without restriction, including without limitation
17   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18   * and/or sell copies of the Software, and to permit persons to whom the
19   * Software is furnished to do so, subject to the following conditions:
20   * 
21   * The above copyright notice and this permission notice shall be included in
22   * all copies or substantial portions of the Software.
23   * 
24   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30   * DEALINGS IN THE SOFTWARE.
31   */
32 /**
33  * This class allows to execute loop statement of VisualBasic .NET
34  */
35
36 using System;
37 using System.Collections;
38
39 namespace Microsoft.VisualBasic.CompilerServices 
40 {
41         [Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute] 
42         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] 
43         sealed public class FlowControl {
44                 private sealed /*static (final)in mainsoft java code*/ class ObjectFor {
45                         public object Counter;
46
47                         public object Limit;
48
49                         public object StepValue;
50
51                         public bool PositiveStep;
52
53                         public Type EnumType;
54                 }
55     
56                 /**
57                  * This method check if the loop can continued.
58                  * if the StepValue is positive it check that count is smaller than the limit.
59                  * if the StepValue is negative it check that count is bigger than the limit. 
60                  * @param count
61                  * @param limit
62                  * @param StepValue
63                  * @return boolean True of the for next loop can continue and false otherwise.
64                  */
65                 public static bool ForNextCheckR4(float count, float limit, float StepValue) {
66                         bool positiveStep = StepValue > 0.0F;
67                         bool isCountSmallThenLimit = count <= limit;
68                         return positiveStep? isCountSmallThenLimit : !isCountSmallThenLimit;
69                 }
70     
71                 /**
72                  * This method check if the loop can continued.
73                  * if the StepValue is positive it check that count is smaller than the limit.
74                  * if the StepValue is negative it check that count is bigger than the limit. 
75                  * @param count
76                  * @param limit
77                  * @param StepValue
78                  * @return boolean True of the for next loop can continue and false otherwise.
79                  */
80                 public static bool ForNextCheckR8(double count, double limit, double StepValue) {
81                         bool positiveStep = StepValue > 0.0;
82                         bool isCountSmallThenLimit = count <= limit;
83                         return positiveStep? isCountSmallThenLimit : !isCountSmallThenLimit;
84                 }
85
86                 /**
87                  * This method check if the loop can continued.
88                  * if the StepValue is positive it check that count is smaller than the limit.
89                  * if the StepValue is negative it check that count is bigger than the limit. 
90                  * @param count
91                  * @param limit
92                  * @param StepValue
93                  * @return boolean True of the for next loop can continue and false otherwise.
94                  */
95                 public static bool ForNextCheckDec(Decimal count, Decimal limit, Decimal StepValue) {
96                         bool positiveStep = StepValue.CompareTo(Decimal.Zero) < 0;
97                         bool isCountSmallThenLimit = count.CompareTo(limit) >= 0;
98                         return positiveStep? isCountSmallThenLimit : !isCountSmallThenLimit; 
99                 }
100     
101                 /**
102                  * This method method updates the LoopFor reference and the Counter reference
103                  * object according to the given params and returns if this loop can continue. 
104                  * @param Counter this loop counter value
105                  * @param Start this loop start value 
106                  * @param Limit this loop limitation value
107                  * @param StepValue this loop step value
108                  * @param lfr the LoopFor reference object
109                  * @param cr the Counter object reference 
110                  * @return boolean is the returned LoopFor object can continue.
111                  */
112                 public static bool ForLoopInitObj(
113                         object Counter,
114                         object Start,
115                         object Limit,
116                         object StepValue,
117                         ref System.Object lfr,
118                         ref System.Object cr) {
119
120                         object CounterResult = cr;
121
122                         if (Start == null) {
123                                 throw new ArgumentException("Argument_InvalidNullValue1 " + " Start");
124                         }
125                         if (Limit == null) {
126                                 throw new ArgumentException("Argument_InvalidNullValue1 " + " Limit");
127                         }
128                         if (StepValue == null) {
129                                 throw new ArgumentException("Argument_InvalidNullValue1 " + " Step");
130                         }
131                         //gets the type of all the given parameters
132                         Type startType = Start.GetType();
133                         Type limitType = Limit.GetType();
134                         Type stepType = StepValue.GetType();
135
136                         //gets the widest common type code
137                 
138                         TypeCode commonTypeCode = ObjectType.GetWidestType(Start, Limit, false);
139                         commonTypeCode = ObjectType.GetWidestType(StepValue, commonTypeCode);
140                         if (commonTypeCode == TypeCode.String) {
141                                 commonTypeCode = TypeCode.Double;
142                         }
143                         if (commonTypeCode == TypeCode.Object) {
144                                 //TODO:
145                                 //throw new ArgumentException(
146                                 //      Utils.GetResourceString(
147                                 //      "ForLoop_CommonType3",
148                                 //      Utils.VBFriendlyName(startType),
149                                 //      Utils.VBFriendlyName(limitType),
150                                 //      Utils.VBFriendlyName(StepValue)));
151                                 throw new ArgumentException("ForLoop_CommonType3 startType limitType StepValue");
152                         }
153
154                         ObjectFor objectFor = new ObjectFor();
155                         TypeCode startTypeCode = Type.GetTypeCode(startType);
156                         TypeCode limitTypeCode = Type.GetTypeCode(limitType);
157                         TypeCode stepTypeCode = Type.GetTypeCode(stepType);
158                         Type enumType = null;
159
160                         bool isStartTypeValidEnum =  (startTypeCode == commonTypeCode) && (startType.IsEnum);
161                         bool isLimitTypeValidEnum =  (limitTypeCode == commonTypeCode) && (limitType.IsEnum);
162                         bool isStepTypeValidEnum =  (stepTypeCode == commonTypeCode) && (stepType.IsEnum);
163         
164                         bool isStartAndStepTypeEqual = (startType == stepType);
165                         bool isStartAndLimitTypeEqual = (startType == limitType);
166                         bool isStepAndLimitTypeEqual = (stepType == limitType);
167
168                         //the For loop has enum type in the following case
169                         //1. step is enum and it's type code equal to commonTypeCode and start and 
170                         //  limit don't meet this condition.
171                         //2. step and start are enum and their type code equal to commonTypeCode and
172                         //  their types are equal. limit doesn't meet this condition about been enum
173                         //  or about been equal to commonTypeCode.
174                         //3. step and limit are enum and their type code equal to commonTypeCode and
175                         //  their types are equal. start doesn't meet this condition about been enum
176                         //  or about been equal to commonTypeCode.
177                         //4. step and limit and start are enum and their type code equal to commonTypeCode and
178                         //  their types are equal.
179                         //5. start is enum and it's type code equal to commonTypeCode .step and 
180                         //  limit don't meet this condition.
181                         //6. limit is enum and it's type code equal to commonTypeCode .step and 
182                         //  start don't meet this condition.
183                         //7.start and limit are enum and their type code equal to commonTypeCode and
184                         //  their types are equal. step doesn't meet this condition about been enum
185                         //  or about been equal to commonTypeCode.
186                         //
187         
188                         if (isStartTypeValidEnum && isLimitTypeValidEnum && isStepTypeValidEnum
189                                 &&  isStartAndStepTypeEqual && isStartAndLimitTypeEqual)
190                                 enumType = startType;
191                         else if (isStartTypeValidEnum && isStepTypeValidEnum && isStartAndStepTypeEqual)
192                                 enumType = startType;
193                         else if (isStartTypeValidEnum && isStepTypeValidEnum && isStartAndStepTypeEqual)
194                                 enumType = startType;
195                         else if (isStartTypeValidEnum && isLimitTypeValidEnum && isStartAndLimitTypeEqual)
196                                 enumType = startType;
197                         else if (isStartTypeValidEnum && !isLimitTypeValidEnum && !isStepTypeValidEnum)
198                                 enumType = startType;
199                         else if (!isStartTypeValidEnum && isLimitTypeValidEnum && !isStepTypeValidEnum)
200                                 enumType = limitType; 
201                         else if (!isStartTypeValidEnum && !isLimitTypeValidEnum && isStepTypeValidEnum)
202                                 enumType = stepType;            
203         
204                         objectFor.EnumType = enumType;
205         
206                         //set the counter field of objectFor with Start value transleted to 
207                         // the widest common type code
208                         objectFor.Counter = convertType(Start, commonTypeCode,"Start");
209                         //set the Limit field of objectFor with Limit value transleted to 
210                         // the widest common type code
211                         objectFor.Limit = convertType(Limit, commonTypeCode,"Limit");
212                         //set the StepValue field of objectFor with StepValue value transleted to 
213                         // the widest common type code
214                         objectFor.StepValue = convertType(StepValue, commonTypeCode,"Step");
215                         //local is the value of zero in the widest common type code
216
217                         object local = ObjectType.CTypeHelper(0, commonTypeCode);
218         
219                         IComparable iComparable = (IComparable)objectFor.StepValue;
220                         objectFor.PositiveStep = iComparable.CompareTo(local) >= 0;
221
222                         // sets the loop for reference 
223                         lfr = objectFor;
224         
225                         //sets the counter reference
226                         if (objectFor.EnumType != null) {
227                                 cr = Enum.ToObject(objectFor.EnumType, objectFor.Counter);
228                         }
229                         else {
230                                 cr = objectFor.Counter;
231                         }        
232                         return CheckContinueLoop(objectFor);
233                 }
234     
235                 private static object convertType(object original, TypeCode typeCode, string fieldName) {
236                         try {
237                                 return ObjectType.CTypeHelper(original, typeCode);
238                         }
239                         catch /*(Exception e)*/ {
240                                 throw new ArgumentException("ForLoop_ConvertToType3 " + fieldName);
241                         }
242                 }
243
244                 public static bool ForNextCheckObj(object Counter, object LoopObj,
245                         ref System.Object CounterResult) {// throws java.lang.Exception
246                         TypeCode generalTypeCode = 0;
247
248                         if (LoopObj == null) {
249                                 //TODO: use resource for the correct execption.
250                                 throw new Exception("VB error message #92 ForNextCheckObj LoopObj cannot be null");
251                                 //throw ExceptionUtils.VbMakeException(92);//correct java version
252                         }
253                         if (Counter == null) {
254                                 throw new NullReferenceException("Argument_InvalidNullValue1 " + " Counter");
255                                 //TODO:
256                                 //throw new NullReferenceException(
257                                 //    Utils.GetResourceString(
258                                 //        "Argument_InvalidNullValue1",
259                                 //        "Counter"));
260                         }
261                          ObjectFor objectFor = (ObjectFor) LoopObj;
262
263                         IConvertible iConvertible_counter = (IConvertible)Counter;
264                         IConvertible iConvertible_step = (IConvertible) objectFor.StepValue;
265
266                         TypeCode counterTypeCode = iConvertible_counter.GetTypeCode();
267                         TypeCode stepTypeCode = iConvertible_step.GetTypeCode();
268                         
269                         if (counterTypeCode == stepTypeCode && counterTypeCode != TypeCode.String) {
270                                 generalTypeCode = counterTypeCode;
271                         }
272                         else {
273                                 generalTypeCode = ObjectType.GetWidestType(counterTypeCode, stepTypeCode);
274                                 if (generalTypeCode == TypeCode.String) {
275                                         generalTypeCode = TypeCode.Double;
276                                 }
277                                 Counter = convertType(Counter, generalTypeCode,"Start");
278                                 objectFor.Limit = convertType(objectFor.Limit, generalTypeCode,"Limit");
279                                 objectFor.StepValue = convertType(objectFor.StepValue, generalTypeCode,"Step");
280                         }
281                         //changes the counter field to be the sum of step and counter 
282                         objectFor.Counter = ObjectType.AddObj(Counter, objectFor.StepValue);
283                         IConvertible iConvertible_objectCounter = (IConvertible)objectFor.Counter;
284                         TypeCode objectCounterTypeCode = iConvertible_objectCounter.GetTypeCode();
285
286                         //setting the counter in counter reference.
287                         //if the for is enum type change counter to enum. 
288                         if (objectFor.EnumType != null) {
289                                 CounterResult = Enum.ToObject(objectFor.EnumType, objectFor.Counter);
290                         }
291                         else {
292                                 CounterResult = objectFor.Counter;
293                         }
294         
295                         //if the counter after the change didn't change it's type return true if 
296                         // the for  object can continue loop and false otherwise.
297                         //if the counter changed it's type change all for object fields to counter
298                         //current type and return false. 
299                         if (objectCounterTypeCode == generalTypeCode) {
300                                 return CheckContinueLoop(objectFor);
301                         }
302                         else {
303                                 objectFor.Limit = ObjectType.CTypeHelper(objectFor.Limit, objectCounterTypeCode);
304         
305                                 objectFor.StepValue =
306                                         ObjectType.CTypeHelper(objectFor.StepValue, objectCounterTypeCode);
307                                 return false;
308                         }
309                 }
310     
311                 /**
312                  * This method returns IEnumertator for a given array
313                  * @param ary the given array
314                  * @return IEnumerator the array's Enumerator
315                  */
316                 public static IEnumerator ForEachInArr(Array ary) {// throws java.lang.Exception
317                         IEnumerator iEnumerator = (IEnumerator)ary;//is ArrayStaticWrapper.GetEnumerator(ary); in java code.
318                         if (iEnumerator != null)
319                                 return iEnumerator;
320                         throw ExceptionUtils.VbMakeException(92);
321                 }
322     
323                 /**
324                  * This method gets IEnumerator for a given object that implements IEnumerable
325                  * @param obj the object that implements IEnumerable
326                  * @return IEnumerator the object's IEnumerator.
327                  */
328                 public static IEnumerator ForEachInObj(object obj) {// throws java.lang.Exception
329                         if (obj == null)
330                                 throw ExceptionUtils.VbMakeException(91);
331
332                         IEnumerable iEnumerable = (IEnumerable)obj;
333                         if (iEnumerable != null) {
334                                 IEnumerator iEnumerator = iEnumerable.GetEnumerator();
335                                 if (iEnumerator != null)
336                                         return iEnumerator;
337                         }
338                         string s = obj.GetType().ToString();
339                         ExceptionUtils.ThrowException1(100, s);
340                         return null;
341                 }
342     
343                 /**
344                  * This method set the next value of teh Enumerator in the reference.
345                  * if there isn't next value , null is been set in the referece. 
346                  * @param obj
347                  * @param enumerator
348                  * @return boolean returns the value of enumerator.MoveNext().
349                  */
350                 public static bool ForEachNextObj(ref System.Object obj, IEnumerator enumerator) {
351                         if (enumerator.MoveNext()) {
352                                 obj = enumerator.Current;
353                                 return true;
354                         }
355                         obj = null;
356                         return false;
357                 }
358     
359                 /**
360                  * This method check if the loop can continued.
361                  * if the step is positive it check that the counter is smaller than the limit.
362                  * if the step is negative it check that the counter is bigger than the limit. 
363                  * @param LoopFor
364                  * @return boolean
365                  */
366                 private static bool CheckContinueLoop(ObjectFor LoopFor) {
367                         //TODO:
368                         //throw new NotImplementedException("MSVB.Compilerservices.flowcontrol needs help");
369                         IComparable iComparable = (IComparable)LoopFor.Counter;
370                         
371                         if (iComparable != null) {
372                                 int i = iComparable.CompareTo(LoopFor.Limit);
373                                 bool isCountSmallThenLimit = i<=0;
374                                 return LoopFor.PositiveStep ? isCountSmallThenLimit : !isCountSmallThenLimit;
375                         }
376                         throw new ArgumentException("Argument_IComparable2 loop control variable"); // + Utils.VBFriendlyName(LoopFor.Counter)));
377                                 //TODO: verify this and the above are the same and remove.
378                                 //throw new ArgumentException(Utils.GetResourceString(
379                                 //      "Argument_IComparable2", "loop control variable",
380                                 //      Utils.VBFriendlyName(LoopFor.Counter)));
381                         }
382     
383                 /**
384                  * This method throws exception if the input is Valuetype  
385                  * @param obj the object that need to be checked
386                  */
387                 public static void CheckForSyncLockOnValueType(object obj) {
388                         //TODO:
389                         //throw new NotImplementedException("MSVB.Compilerservices.flowcontrol needs help");
390                         if (obj != null && obj.GetType().IsValueType)
391                                 throw new ArgumentException(Utils.GetResourceString("SyncLockRequiresReferenceType1 "));
392                         //TODO: verify this and the above are the same and remove.
393                         //if (obj != null && ObjectStaticWrapper.GetType(obj).get_IsValueType())
394                         //      throw new ArgumentException(Utils.GetResourceString(
395                         //              "SyncLockRequiresReferenceType1",Utils.VBFriendlyName(obj)));
396                 }
397         }
398 }