* Interaction.cs :
[mono.git] / mcs / class / 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 using System.ComponentModel;
39
40 namespace Microsoft.VisualBasic.CompilerServices 
41 {
42         [StandardModule, EditorBrowsable(EditorBrowsableState.Never)] 
43         sealed public class FlowControl {
44                 private FlowControl () {}
45
46                 private sealed /*static (final)in mainsoft java code*/ class ObjectFor {
47                         public object Counter;
48
49                         public object Limit;
50
51                         public object StepValue;
52
53                         public bool PositiveStep;
54
55                         public Type EnumType;
56                 }
57     
58                 /**
59                  * This method check if the loop can continued.
60                  * if the StepValue is positive it check that count is smaller than the limit.
61                  * if the StepValue is negative it check that count is bigger than the limit. 
62                  * @param count
63                  * @param limit
64                  * @param StepValue
65                  * @return boolean True of the for next loop can continue and false otherwise.
66                  */
67                 public static bool ForNextCheckR4(float count, float limit, float StepValue) {
68                         bool positiveStep = StepValue > 0.0F;
69                         if (positiveStep)
70                                 return count <= limit;
71                         else
72                                 return count >= limit;
73                 }
74     
75                 /**
76                  * This method check if the loop can continued.
77                  * if the StepValue is positive it check that count is smaller than the limit.
78                  * if the StepValue is negative it check that count is bigger than the limit. 
79                  * @param count
80                  * @param limit
81                  * @param StepValue
82                  * @return boolean True of the for next loop can continue and false otherwise.
83                  */
84                 public static bool ForNextCheckR8(double count, double limit, double StepValue) {
85                         bool positiveStep = StepValue > 0.0;
86                         if (positiveStep)
87                                 return count <= limit;
88                         else
89                                 return count >= limit;
90                 }
91
92                 /**
93                  * This method check if the loop can continued.
94                  * if the StepValue is positive it check that count is smaller than the limit.
95                  * if the StepValue is negative it check that count is bigger than the limit. 
96                  * @param count
97                  * @param limit
98                  * @param StepValue
99                  * @return boolean True of the for next loop can continue and false otherwise.
100                  */
101                 public static bool ForNextCheckDec(Decimal count, Decimal limit, Decimal StepValue) {
102                         bool positiveStep = StepValue.CompareTo(Decimal.Zero) > 0;
103                         if (positiveStep)
104                                 return (count.CompareTo(limit) <= 0);
105                         else 
106                                 return (limit.CompareTo(count) <= 0);
107                 }
108     
109                 /**
110                  * This method method updates the LoopFor reference and the Counter reference
111                  * object according to the given params and returns if this loop can continue. 
112                  * @param Counter this loop counter value
113                  * @param Start this loop start value 
114                  * @param Limit this loop limitation value
115                  * @param StepValue this loop step value
116                  * @param lfr the LoopFor reference object
117                  * @param cr the Counter object reference 
118                  * @return boolean is the returned LoopFor object can continue.
119                  */
120                 public static bool ForLoopInitObj(
121                         object Counter,
122                         object Start,
123                         object Limit,
124                         object StepValue,
125                         ref System.Object lfr,
126                         ref System.Object cr) {
127
128                         if (Start == null) {
129                                 throw new ArgumentException("Argument_InvalidNullValue1 " + " Start");
130                         }
131                         if (Limit == null) {
132                                 throw new ArgumentException("Argument_InvalidNullValue1 " + " Limit");
133                         }
134                         if (StepValue == null) {
135                                 throw new ArgumentException("Argument_InvalidNullValue1 " + " Step");
136                         }
137                         //gets the type of all the given parameters
138                         Type startType = Start.GetType();
139                         Type limitType = Limit.GetType();
140                         Type stepType = StepValue.GetType();
141
142                         //gets the widest common type code
143                 
144                         TypeCode commonTypeCode = ObjectType.GetWidestType(Start, Limit, false);
145                         commonTypeCode = ObjectType.GetWidestType(StepValue, commonTypeCode);
146                         if (commonTypeCode == TypeCode.String) {
147                                 commonTypeCode = TypeCode.Double;
148                         }
149                         if (commonTypeCode == TypeCode.Object) {
150                                 //TODO:
151                                 //throw new ArgumentException(
152                                 //      Utils.GetResourceString(
153                                 //      "ForLoop_CommonType3",
154                                 //      Utils.VBFriendlyName(startType),
155                                 //      Utils.VBFriendlyName(limitType),
156                                 //      Utils.VBFriendlyName(StepValue)));
157                                 throw new ArgumentException("ForLoop_CommonType3 startType limitType StepValue");
158                         }
159
160                         ObjectFor objectFor = new ObjectFor();
161                         TypeCode startTypeCode = Type.GetTypeCode(startType);
162                         TypeCode limitTypeCode = Type.GetTypeCode(limitType);
163                         TypeCode stepTypeCode = Type.GetTypeCode(stepType);
164                         Type enumType = null;
165
166                         bool isStartTypeValidEnum =  (startTypeCode == commonTypeCode) && (startType.IsEnum);
167                         bool isLimitTypeValidEnum =  (limitTypeCode == commonTypeCode) && (limitType.IsEnum);
168                         bool isStepTypeValidEnum =  (stepTypeCode == commonTypeCode) && (stepType.IsEnum);
169         
170                         bool isStartAndStepTypeEqual = (startType == stepType);
171                         bool isStartAndLimitTypeEqual = (startType == limitType);
172                         // bool isStepAndLimitTypeEqual = (stepType == limitType);
173
174                         //the For loop has enum type in the following case
175                         //1. step is enum and it's type code equal to commonTypeCode and start and 
176                         //  limit don't meet this condition.
177                         //2. step and start are enum and their type code equal to commonTypeCode and
178                         //  their types are equal. limit doesn't meet this condition about been enum
179                         //  or about been equal to commonTypeCode.
180                         //3. step and limit are enum and their type code equal to commonTypeCode and
181                         //  their types are equal. start doesn't meet this condition about been enum
182                         //  or about been equal to commonTypeCode.
183                         //4. step and limit and start are enum and their type code equal to commonTypeCode and
184                         //  their types are equal.
185                         //5. start is enum and it's type code equal to commonTypeCode .step and 
186                         //  limit don't meet this condition.
187                         //6. limit is enum and it's type code equal to commonTypeCode .step and 
188                         //  start don't meet this condition.
189                         //7.start and limit are enum and their type code equal to commonTypeCode and
190                         //  their types are equal. step doesn't meet this condition about been enum
191                         //  or about been equal to commonTypeCode.
192                         //
193         
194                         if (isStartTypeValidEnum && isLimitTypeValidEnum && isStepTypeValidEnum
195                                 &&  isStartAndStepTypeEqual && isStartAndLimitTypeEqual)
196                                 enumType = startType;
197                         else if (isStartTypeValidEnum && isStepTypeValidEnum && isStartAndStepTypeEqual)
198                                 enumType = startType;
199                         else if (isStartTypeValidEnum && isStepTypeValidEnum && isStartAndStepTypeEqual)
200                                 enumType = startType;
201                         else if (isStartTypeValidEnum && isLimitTypeValidEnum && isStartAndLimitTypeEqual)
202                                 enumType = startType;
203                         else if (isStartTypeValidEnum && !isLimitTypeValidEnum && !isStepTypeValidEnum)
204                                 enumType = startType;
205                         else if (!isStartTypeValidEnum && isLimitTypeValidEnum && !isStepTypeValidEnum)
206                                 enumType = limitType; 
207                         else if (!isStartTypeValidEnum && !isLimitTypeValidEnum && isStepTypeValidEnum)
208                                 enumType = stepType;            
209         
210                         objectFor.EnumType = enumType;
211         
212                         //set the counter field of objectFor with Start value transleted to 
213                         // the widest common type code
214                         objectFor.Counter = convertType(Start, commonTypeCode,"Start");
215                         //set the Limit field of objectFor with Limit value transleted to 
216                         // the widest common type code
217                         objectFor.Limit = convertType(Limit, commonTypeCode,"Limit");
218                         //set the StepValue field of objectFor with StepValue value transleted to 
219                         // the widest common type code
220                         objectFor.StepValue = convertType(StepValue, commonTypeCode,"Step");
221                         //local is the value of zero in the widest common type code
222
223                         object local = ObjectType.CTypeHelper(0, commonTypeCode);
224         
225                         IComparable iComparable = (IComparable)objectFor.StepValue;
226                         objectFor.PositiveStep = iComparable.CompareTo(local) >= 0;
227
228                         // sets the loop for reference 
229                         lfr = objectFor;
230         
231                         //sets the counter reference
232                         if (objectFor.EnumType != null) {
233                                 cr = Enum.ToObject(objectFor.EnumType, objectFor.Counter);
234                         }
235                         else {
236                                 cr = objectFor.Counter;
237                         }        
238                         return CheckContinueLoop(objectFor);
239                 }
240     
241                 private static object convertType(object original, TypeCode typeCode, string fieldName) {
242                         try {
243                                 return ObjectType.CTypeHelper(original, typeCode);
244                         }
245                         catch /*(Exception e)*/ {
246                                 throw new ArgumentException("ForLoop_ConvertToType3 " + fieldName);
247                         }
248                 }
249
250                 public static bool ForNextCheckObj(object Counter, object LoopObj,
251                         ref System.Object CounterResult) {// throws java.lang.Exception
252                         TypeCode generalTypeCode = 0;
253
254                         if (LoopObj == null) {
255                                 //TODO: use resource for the correct execption.
256                                 throw new Exception("VB error message #92 ForNextCheckObj LoopObj cannot be null");
257                                 //throw ExceptionUtils.VbMakeException(92);//correct java version
258                         }
259                         if (Counter == null) {
260                                 throw new NullReferenceException("Argument_InvalidNullValue1 " + " Counter");
261                                 //TODO:
262                                 //throw new NullReferenceException(
263                                 //    Utils.GetResourceString(
264                                 //        "Argument_InvalidNullValue1",
265                                 //        "Counter"));
266                         }
267                          ObjectFor objectFor = (ObjectFor) LoopObj;
268
269                         IConvertible iConvertible_counter = (IConvertible)Counter;
270                         IConvertible iConvertible_step = (IConvertible) objectFor.StepValue;
271
272                         TypeCode counterTypeCode = iConvertible_counter.GetTypeCode();
273                         TypeCode stepTypeCode = iConvertible_step.GetTypeCode();
274                         
275                         if (counterTypeCode == stepTypeCode && counterTypeCode != TypeCode.String) {
276                                 generalTypeCode = counterTypeCode;
277                         }
278                         else {
279                                 generalTypeCode = ObjectType.GetWidestType(counterTypeCode, stepTypeCode);
280                                 if (generalTypeCode == TypeCode.String) {
281                                         generalTypeCode = TypeCode.Double;
282                                 }
283                                 Counter = convertType(Counter, generalTypeCode,"Start");
284                                 objectFor.Limit = convertType(objectFor.Limit, generalTypeCode,"Limit");
285                                 objectFor.StepValue = convertType(objectFor.StepValue, generalTypeCode,"Step");
286                         }
287                         //changes the counter field to be the sum of step and counter 
288                         objectFor.Counter = ObjectType.AddObj(Counter, objectFor.StepValue);
289                         IConvertible iConvertible_objectCounter = (IConvertible)objectFor.Counter;
290                         TypeCode objectCounterTypeCode = iConvertible_objectCounter.GetTypeCode();
291
292                         //setting the counter in counter reference.
293                         //if the for is enum type change counter to enum. 
294                         if (objectFor.EnumType != null) {
295                                 CounterResult = Enum.ToObject(objectFor.EnumType, objectFor.Counter);
296                         }
297                         else {
298                                 CounterResult = objectFor.Counter;
299                         }
300         
301                         //if the counter after the change didn't change it's type return true if 
302                         // the for  object can continue loop and false otherwise.
303                         //if the counter changed it's type change all for object fields to counter
304                         //current type and return false. 
305                         if (objectCounterTypeCode == generalTypeCode) {
306                                 return CheckContinueLoop(objectFor);
307                         }
308                         else {
309                                 objectFor.Limit = ObjectType.CTypeHelper(objectFor.Limit, objectCounterTypeCode);
310         
311                                 objectFor.StepValue =
312                                         ObjectType.CTypeHelper(objectFor.StepValue, objectCounterTypeCode);
313                                 return false;
314                         }
315                 }
316     
317                 /**
318                  * This method returns IEnumertator for a given array
319                  * @param ary the given array
320                  * @return IEnumerator the array's Enumerator
321                  */
322                 public static IEnumerator ForEachInArr(Array ary) {// throws java.lang.Exception
323                         IEnumerator iEnumerator = (IEnumerator)ary;//is ArrayStaticWrapper.GetEnumerator(ary); in java code.
324                         if (iEnumerator != null)
325                                 return iEnumerator;
326                         throw ExceptionUtils.VbMakeException(92);
327                 }
328     
329                 /**
330                  * This method gets IEnumerator for a given object that implements IEnumerable
331                  * @param obj the object that implements IEnumerable
332                  * @return IEnumerator the object's IEnumerator.
333                  */
334                 public static IEnumerator ForEachInObj(object obj) {// throws java.lang.Exception
335                         if (obj == null)
336                                 throw ExceptionUtils.VbMakeException(91);
337
338                         IEnumerable iEnumerable = (IEnumerable)obj;
339                         if (iEnumerable != null) {
340                                 IEnumerator iEnumerator = iEnumerable.GetEnumerator();
341                                 if (iEnumerator != null)
342                                         return iEnumerator;
343                         }
344                         string s = obj.GetType().ToString();
345                         ExceptionUtils.ThrowException1(100, s);
346                         return null;
347                 }
348     
349                 /**
350                  * This method set the next value of teh Enumerator in the reference.
351                  * if there isn't next value , null is been set in the referece. 
352                  * @param obj
353                  * @param enumerator
354                  * @return boolean returns the value of enumerator.MoveNext().
355                  */
356                 public static bool ForEachNextObj(ref System.Object obj, IEnumerator enumerator) {
357                         if (enumerator.MoveNext()) {
358                                 obj = enumerator.Current;
359                                 return true;
360                         }
361                         obj = null;
362                         return false;
363                 }
364     
365                 /**
366                  * This method check if the loop can continued.
367                  * if the step is positive it check that the counter is smaller than the limit.
368                  * if the step is negative it check that the counter is bigger than the limit. 
369                  * @param LoopFor
370                  * @return boolean
371                  */
372                 private static bool CheckContinueLoop(ObjectFor LoopFor) {
373                         //TODO:
374                         //throw new NotImplementedException("MSVB.Compilerservices.flowcontrol needs help");
375                         IComparable iComparable = (IComparable)LoopFor.Counter;
376                         
377                         if (iComparable != null) {
378                                 int i = iComparable.CompareTo(LoopFor.Limit);
379                                 if (LoopFor.PositiveStep)
380                                         return i <= 0;
381                                 else
382                                         return i >= 0;
383                         }
384                         throw new ArgumentException("Argument_IComparable2 loop control variable"); // + Utils.VBFriendlyName(LoopFor.Counter)));
385                                 //TODO: verify this and the above are the same and remove.
386                                 //throw new ArgumentException(Utils.GetResourceString(
387                                 //      "Argument_IComparable2", "loop control variable",
388                                 //      Utils.VBFriendlyName(LoopFor.Counter)));
389                         }
390     
391                 /**
392                  * This method throws exception if the input is Valuetype  
393                  * @param obj the object that need to be checked
394                  */
395                 public static void CheckForSyncLockOnValueType(object obj) {
396                         //TODO:
397                         //throw new NotImplementedException("MSVB.Compilerservices.flowcontrol needs help");
398                         if (obj != null && obj.GetType().IsValueType)
399                                 throw new ArgumentException(Utils.GetResourceString("SyncLockRequiresReferenceType1 "));
400                         //TODO: verify this and the above are the same and remove.
401                         //if (obj != null && ObjectStaticWrapper.GetType(obj).get_IsValueType())
402                         //      throw new ArgumentException(Utils.GetResourceString(
403                         //              "SyncLockRequiresReferenceType1",Utils.VBFriendlyName(obj)));
404                 }
405         }
406 }