2004-04-02 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / gmcs / attribute.cs
1 // -*- coding: dos -*-
2 //\r
3 // attribute.cs: Attribute Handler\r
4 //\r
5 // Author: Ravi Pratap (ravi@ximian.com)\r
6 //\r
7 // Licensed under the terms of the GNU GPL\r
8 //\r
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)\r
10 //\r
11 //\r
12 \r
13 using System;\r
14 using System.Diagnostics;\r
15 using System.Collections;\r
16 using System.Reflection;\r
17 using System.Reflection.Emit;\r
18 using System.Runtime.InteropServices;\r
19 using System.Runtime.CompilerServices;\r
20 using System.Text;\r
21 \r
22 namespace Mono.CSharp {\r
23 \r
24         public class Attribute {\r
25                 public readonly string    Name;\r
26                 public readonly ArrayList Arguments;\r
27 \r
28                 Location Location;\r
29 \r
30                 public Type Type;\r
31                 \r
32                 //\r
33                 // The following are only meaningful when the attribute\r
34                 // being emitted is an AttributeUsage attribute\r
35                 //\r
36                 AttributeTargets Targets;\r
37                 bool AllowMultiple;\r
38                 bool Inherited;\r
39 \r
40                 bool UsageAttr = false;\r
41                 \r
42                 MethodImplOptions ImplOptions;\r
43                 UnmanagedType     UnmanagedType;\r
44                 CustomAttributeBuilder cb;\r
45         \r
46                 // non-null if named args present after Resolve () is called\r
47                 PropertyInfo [] prop_info_arr;\r
48                 FieldInfo [] field_info_arr;\r
49                 object [] field_values_arr;\r
50                 object [] prop_values_arr;\r
51                 \r
52                 public Attribute (string name, ArrayList args, Location loc)\r
53                 {\r
54                         Name = name;\r
55                         Arguments = args;\r
56                         Location = loc;\r
57                 }\r
58 \r
59                 void Error_InvalidNamedArgument (string name)\r
60                 {\r
61                         Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +\r
62                                       "argument. Named attribute arguments must be fields which are not " +\r
63                                       "readonly, static or const, or properties with a set accessor which "+\r
64                                       "are not static.");\r
65                 }\r
66 \r
67                 static void Error_AttributeArgumentNotValid (Location loc)\r
68                 {\r
69                         Report.Error (182, loc,\r
70                                       "An attribute argument must be a constant expression, typeof " +\r
71                                       "expression or array creation expression");\r
72                 }\r
73 \r
74                 static void Error_AttributeConstructorMismatch (Location loc)\r
75                 {\r
76                         Report.Error (-6, loc,\r
77                                       "Could not find a constructor for this argument list.");\r
78                 }\r
79 \r
80                 static void Error_TypeParameterInAttribute (Location loc)\r
81                 {\r
82                         Report.Error (\r
83                                 -202, loc, "Can not use a type parameter in an attribute");\r
84                 }\r
85 \r
86                 /// <summary>\r
87                 ///   Tries to resolve the type of the attribute. Flags an error if it can't.\r
88                 /// </summary>\r
89                 private Type CheckAttributeType (EmitContext ec) {\r
90                         Type t;\r
91                         bool isattributeclass = true;\r
92                         \r
93                         t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);\r
94                         if (t != null) {\r
95                                 isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);\r
96                                 if (isattributeclass)\r
97                                         return t;\r
98                         }\r
99                         t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);\r
100                         if (t != null) {\r
101                                 if (t.IsSubclassOf (TypeManager.attribute_type))\r
102                                         return t;\r
103                         }\r
104                         if (!isattributeclass) {\r
105                                 Report.Error (616, Location, "'" + Name + "': is not an attribute class");\r
106                                 return null;\r
107                         }\r
108                         if (t != null) {\r
109                                 Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");\r
110                                 return null;\r
111                         }\r
112                         Report.Error (\r
113                                 246, Location, "Could not find attribute '" + Name + "' (are you" +\r
114                                 " missing a using directive or an assembly reference ?)");\r
115                         return null;\r
116                 }\r
117 \r
118                 public Type ResolveType (EmitContext ec)\r
119                 {\r
120                         Type = CheckAttributeType (ec);\r
121                         return Type;\r
122                 }\r
123 \r
124                 /// <summary>\r
125                 ///   Validates the guid string\r
126                 /// </summary>\r
127                 bool ValidateGuid (string guid)\r
128                 {\r
129                         try {\r
130                                 new Guid (guid);\r
131                                 return true;\r
132                         } catch {\r
133                                 Report.Error (647, Location, "Format of GUID is invalid: " + guid);\r
134                                 return false;\r
135                         }\r
136                 }\r
137 \r
138                 //\r
139                 // Given an expression, if the expression is a valid attribute-argument-expression\r
140                 // returns an object that can be used to encode it, or null on failure.\r
141                 //\r
142                 public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)\r
143                 {\r
144                         if (e is Constant) {\r
145                                 result = ((Constant) e).GetValue ();\r
146                                 return true;\r
147                         } else if (e is TypeOf) {\r
148                                 result = ((TypeOf) e).TypeArg;\r
149                                 return true;\r
150                         } else if (e is ArrayCreation){\r
151                                 result =  ((ArrayCreation) e).EncodeAsAttribute ();\r
152                                 if (result != null)\r
153                                         return true;\r
154                         } else if (e is EmptyCast) {\r
155                                 result = e;\r
156                                 if (((EmptyCast) e).Child is Constant) {\r
157                                         result = ((Constant) ((EmptyCast)e).Child).GetValue();\r
158                                 }\r
159                                 return true;\r
160                         }\r
161 \r
162                         result = null;\r
163                         Error_AttributeArgumentNotValid (loc);\r
164                         return false;\r
165                 }\r
166                 \r
167                 public CustomAttributeBuilder Resolve (EmitContext ec)\r
168                 {\r
169                         if (Type == null)\r
170                                 Type = CheckAttributeType (ec);\r
171                         if (Type == null)\r
172                                 return null;\r
173 \r
174                         bool MethodImplAttr = false;\r
175                         bool MarshalAsAttr = false;\r
176                         bool GuidAttr = false;\r
177                         UsageAttr = false;\r
178 \r
179                         bool DoCompares = true;\r
180 \r
181                         //\r
182                         // If we are a certain special attribute, we\r
183                         // set the information accordingly\r
184                         //\r
185                         \r
186                         if (Type == TypeManager.attribute_usage_type)\r
187                                 UsageAttr = true;\r
188                         else if (Type == TypeManager.methodimpl_attr_type)\r
189                                 MethodImplAttr = true;\r
190                         else if (Type == TypeManager.marshal_as_attr_type)\r
191                                 MarshalAsAttr = true;\r
192                         else if (Type == TypeManager.guid_attr_type)\r
193                                 GuidAttr = true;\r
194                         else\r
195                                 DoCompares = false;\r
196 \r
197                         // Now we extract the positional and named arguments\r
198                         \r
199                         ArrayList pos_args = new ArrayList ();\r
200                         ArrayList named_args = new ArrayList ();\r
201                         int pos_arg_count = 0;\r
202                         \r
203                         if (Arguments != null) {\r
204                                 pos_args = (ArrayList) Arguments [0];\r
205                                 if (pos_args != null)\r
206                                         pos_arg_count = pos_args.Count;\r
207                                 if (Arguments.Count > 1)\r
208                                         named_args = (ArrayList) Arguments [1];\r
209                         }\r
210 \r
211                         object [] pos_values = new object [pos_arg_count];\r
212 \r
213                         //\r
214                         // First process positional arguments \r
215                         //\r
216 \r
217                         int i;\r
218                         for (i = 0; i < pos_arg_count; i++) {\r
219                                 Argument a = (Argument) pos_args [i];\r
220                                 Expression e;\r
221 \r
222                                 if (!a.Resolve (ec, Location))\r
223                                         return null;\r
224 \r
225                                 e = a.Expr;\r
226 \r
227                                 object val;\r
228                                 if (!GetAttributeArgumentExpression (e, Location, out val))\r
229                                         return null;\r
230                                 \r
231                                 pos_values [i] = val;\r
232                                 if (DoCompares){\r
233                                         if (UsageAttr)\r
234                                                 this.Targets = (AttributeTargets) pos_values [0];\r
235                                         else if (MethodImplAttr)\r
236                                                 this.ImplOptions = (MethodImplOptions) pos_values [0];\r
237                                         else if (GuidAttr){\r
238                                                 //\r
239                                                 // we will later check the validity of the type\r
240                                                 //\r
241                                                 if (pos_values [0] is string){\r
242                                                         if (!ValidateGuid ((string) pos_values [0]))\r
243                                                                 return null;\r
244                                                 }\r
245                                                 \r
246                                         } else if (MarshalAsAttr)\r
247                                                 this.UnmanagedType =\r
248                                                 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];\r
249                                 }\r
250                         }\r
251 \r
252                         //\r
253                         // Now process named arguments\r
254                         //\r
255 \r
256                         ArrayList field_infos = null;\r
257                         ArrayList prop_infos  = null;\r
258                         ArrayList field_values = null;\r
259                         ArrayList prop_values = null;\r
260 \r
261                         if (named_args.Count > 0) {\r
262                                 field_infos = new ArrayList ();\r
263                                 prop_infos  = new ArrayList ();\r
264                                 field_values = new ArrayList ();\r
265                                 prop_values = new ArrayList ();\r
266                         }\r
267                         \r
268                         for (i = 0; i < named_args.Count; i++) {\r
269                                 DictionaryEntry de = (DictionaryEntry) named_args [i];\r
270                                 string member_name = (string) de.Key;\r
271                                 Argument a  = (Argument) de.Value;\r
272                                 Expression e;\r
273                                 \r
274                                 if (!a.Resolve (ec, Location))\r
275                                         return null;\r
276 \r
277                                 Expression member = Expression.MemberLookup (\r
278                                         ec, Type, member_name,\r
279                                         MemberTypes.Field | MemberTypes.Property,\r
280                                         BindingFlags.Public | BindingFlags.Instance,\r
281                                         Location);\r
282 \r
283                                 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {\r
284                                         Error_InvalidNamedArgument (member_name);\r
285                                         return null;\r
286                                 }\r
287 \r
288                                 e = a.Expr;\r
289                                 if (e is TypeParameterExpr){\r
290                                         Error_TypeParameterInAttribute (Location);\r
291                                         return null;\r
292                                 }\r
293                                         \r
294                                 if (member is PropertyExpr) {\r
295                                         PropertyExpr pe = (PropertyExpr) member;\r
296                                         PropertyInfo pi = pe.PropertyInfo;\r
297 \r
298                                         if (!pi.CanWrite) {\r
299                                                 Error_InvalidNamedArgument (member_name);\r
300                                                 return null;\r
301                                         }\r
302 \r
303                                         if (e is Constant) {\r
304                                                 object o = ((Constant) e).GetValue ();\r
305                                                 prop_values.Add (o);\r
306                                                 \r
307                                                 if (UsageAttr) {\r
308                                                         if (member_name == "AllowMultiple")\r
309                                                                 this.AllowMultiple = (bool) o;\r
310                                                         if (member_name == "Inherited")\r
311                                                                 this.Inherited = (bool) o;\r
312                                                 }\r
313                                                 \r
314                                         } else if (e is TypeOf) {\r
315                                                 prop_values.Add (((TypeOf) e).TypeArg);\r
316                                         } else if (e is ArrayCreation) {\r
317                                                 prop_values.Add (((ArrayCreation) e).EncodeAsAttribute());\r
318                                         } else {\r
319                                                 Error_AttributeArgumentNotValid (Location);\r
320                                                 return null;\r
321                                         }\r
322                                         \r
323                                         prop_infos.Add (pi);\r
324                                         \r
325                                 } else if (member is FieldExpr) {\r
326                                         FieldExpr fe = (FieldExpr) member;\r
327                                         FieldInfo fi = fe.FieldInfo;\r
328 \r
329                                         if (fi.IsInitOnly) {\r
330                                                 Error_InvalidNamedArgument (member_name);\r
331                                                 return null;\r
332                                         }\r
333 \r
334                                         //\r
335                                         // Handle charset here, and set the TypeAttributes\r
336                                         \r
337                                         if (e is Constant){\r
338                                                 object value = ((Constant) e).GetValue ();\r
339                                                 \r
340                                                 field_values.Add (value);\r
341                                         } else if (e is TypeOf) {\r
342                                                 field_values.Add (((TypeOf) e).TypeArg);\r
343                                         } else {\r
344                                                 Error_AttributeArgumentNotValid (Location);\r
345                                                 return null;\r
346                                         }\r
347                                         \r
348                                         field_infos.Add (fi);\r
349                                 }\r
350                         }\r
351 \r
352                         Expression mg = Expression.MemberLookup (\r
353                                 ec, Type, ".ctor", MemberTypes.Constructor,\r
354                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,\r
355                                 Location);\r
356 \r
357                         if (mg == null) {\r
358                                 Error_AttributeConstructorMismatch (Location);\r
359                                 return null;\r
360                         }\r
361 \r
362                         MethodBase constructor = Invocation.OverloadResolve (\r
363                                 ec, (MethodGroupExpr) mg, pos_args, false, Location);\r
364 \r
365                         if (constructor == null) {\r
366                                 Error_AttributeConstructorMismatch (Location);\r
367                                 return null;\r
368                         }\r
369 \r
370                         //\r
371                         // Now we perform some checks on the positional args as they\r
372                         // cannot be null for a constructor which expects a parameter\r
373                         // of type object\r
374                         //\r
375 \r
376                         ParameterData pd = Invocation.GetParameterData (constructor);\r
377 \r
378                         int group_in_params_array = Int32.MaxValue;\r
379                         int pc = pd.Count;\r
380                         if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)\r
381                                 group_in_params_array = pc-1;\r
382                         \r
383                         for (int j = 0; j < pos_arg_count; ++j) {\r
384                                 Argument a = (Argument) pos_args [j];\r
385                                 \r
386                                 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {\r
387                                         Error_AttributeArgumentNotValid (Location);\r
388                                         return null;\r
389                                 }\r
390 \r
391                                 if (j < group_in_params_array)\r
392                                         continue;\r
393                                 \r
394                                 if (j == group_in_params_array){\r
395                                         object v = pos_values [j];\r
396                                         int count = pos_arg_count - j;\r
397 \r
398                                         object [] array = new object [count];\r
399                                         pos_values [j] = array;\r
400                                         array [0] = v;\r
401                                 } else {\r
402                                         object [] array = (object []) pos_values [group_in_params_array];\r
403 \r
404                                         array [j - group_in_params_array] = pos_values [j];\r
405                                 }\r
406                         }\r
407 \r
408                         //\r
409                         // Adjust the size of the pos_values if it had params\r
410                         //\r
411                         if (group_in_params_array != Int32.MaxValue){\r
412                                 int argc = group_in_params_array+1;\r
413                                 object [] new_pos_values = new object [argc];\r
414 \r
415                                 for (int p = 0; p < argc; p++)\r
416                                         new_pos_values [p] = pos_values [p];\r
417                                 pos_values = new_pos_values;\r
418                         }\r
419 \r
420                         try {\r
421                                 if (named_args.Count > 0) {\r
422                                         prop_info_arr = new PropertyInfo [prop_infos.Count];\r
423                                         field_info_arr = new FieldInfo [field_infos.Count];\r
424                                         field_values_arr = new object [field_values.Count];\r
425                                         prop_values_arr = new object [prop_values.Count];\r
426 \r
427                                         field_infos.CopyTo  (field_info_arr, 0);\r
428                                         field_values.CopyTo (field_values_arr, 0);\r
429 \r
430                                         prop_values.CopyTo  (prop_values_arr, 0);\r
431                                         prop_infos.CopyTo   (prop_info_arr, 0);\r
432 \r
433                                         cb = new CustomAttributeBuilder (\r
434                                                 (ConstructorInfo) constructor, pos_values,\r
435                                                 prop_info_arr, prop_values_arr,\r
436                                                 field_info_arr, field_values_arr);\r
437                                 }\r
438                                 else\r
439                                         cb = new CustomAttributeBuilder (\r
440                                                 (ConstructorInfo) constructor, pos_values);\r
441                         } catch (NullReferenceException) {\r
442                                 // \r
443                                 // Don't know what to do here\r
444                                 //\r
445                                 Report.Warning (\r
446                                         -101, Location, "NullReferenceException while trying to create attribute." +\r
447                                         "Something's wrong!");\r
448                         } catch (Exception e) {\r
449                                 //\r
450                                 // Sample:\r
451                                 // using System.ComponentModel;\r
452                                 // [DefaultValue (CollectionChangeAction.Add)]\r
453                                 // class X { static void Main () {} }\r
454                                 //\r
455                                 Report.Warning (\r
456                                         -23, Location,\r
457                                         "The compiler can not encode this attribute in .NET due to\n" +\r
458                                         "\ta bug in the .NET runtime.  Try the Mono runtime.\nThe error was: " + e.Message);\r
459                         }\r
460                         \r
461                         return cb;\r
462                 }\r
463 \r
464                 /// <summary>\r
465                 ///   Get a string containing a list of valid targets for the attribute 'attr'\r
466                 /// </summary>\r
467                 static string GetValidTargets (Attribute attr)\r
468                 {\r
469                         StringBuilder sb = new StringBuilder ();\r
470                         AttributeTargets targets = 0;\r
471                         \r
472                         TypeContainer a = TypeManager.LookupAttr (attr.Type);\r
473 \r
474                         if (a == null) {\r
475                                 \r
476                                 System.Attribute [] attrs = null;\r
477                                 \r
478                                 try {\r
479                                         attrs = System.Attribute.GetCustomAttributes (attr.Type);\r
480                                         \r
481                                 } catch {\r
482                                         Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +\r
483                                                       " (maybe you forgot to set the usage using the" +\r
484                                                       " AttributeUsage attribute ?).");\r
485                                         return null;\r
486                                 }\r
487                                         \r
488                                 foreach (System.Attribute tmp in attrs)\r
489                                         if (tmp is AttributeUsageAttribute) {\r
490                                                 targets = ((AttributeUsageAttribute) tmp).ValidOn;\r
491                                                 break;\r
492                                         }\r
493                         } else\r
494                                 targets = a.Targets;\r
495 \r
496                         \r
497                         if ((targets & AttributeTargets.Assembly) != 0)\r
498                                 sb.Append ("'assembly' ");\r
499 \r
500                         if ((targets & AttributeTargets.Class) != 0)\r
501                                 sb.Append ("'class' ");\r
502 \r
503                         if ((targets & AttributeTargets.Constructor) != 0)\r
504                                 sb.Append ("'constructor' ");\r
505 \r
506                         if ((targets & AttributeTargets.Delegate) != 0)\r
507                                 sb.Append ("'delegate' ");\r
508 \r
509                         if ((targets & AttributeTargets.Enum) != 0)\r
510                                 sb.Append ("'enum' ");\r
511 \r
512                         if ((targets & AttributeTargets.Event) != 0)\r
513                                 sb.Append ("'event' ");\r
514 \r
515                         if ((targets & AttributeTargets.Field) != 0)\r
516                                 sb.Append ("'field' ");\r
517 \r
518                         if ((targets & AttributeTargets.Interface) != 0)\r
519                                 sb.Append ("'interface' ");\r
520 \r
521                         if ((targets & AttributeTargets.Method) != 0)\r
522                                 sb.Append ("'method' ");\r
523 \r
524                         if ((targets & AttributeTargets.Module) != 0)\r
525                                 sb.Append ("'module' ");\r
526 \r
527                         if ((targets & AttributeTargets.Parameter) != 0)\r
528                                 sb.Append ("'parameter' ");\r
529 \r
530                         if ((targets & AttributeTargets.Property) != 0)\r
531                                 sb.Append ("'property' ");\r
532 \r
533                         if ((targets & AttributeTargets.ReturnValue) != 0)\r
534                                 sb.Append ("'return value' ");\r
535 \r
536                         if ((targets & AttributeTargets.Struct) != 0)\r
537                                 sb.Append ("'struct' ");\r
538 \r
539                         return sb.ToString ();\r
540 \r
541                 }\r
542 \r
543                 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)\r
544                 {\r
545                         Report.Error (\r
546                                 592, loc, "Attribute '" + a.Name +\r
547                                 "' is not valid on this declaration type. " +\r
548                                 "It is valid on " + GetValidTargets (a) + "declarations only.");\r
549                 }\r
550 \r
551                 /// <summary>\r
552                 ///   Ensure that Attribute 'a' is being applied to the right language element (target)\r
553                 /// </summary>\r
554                 public static bool CheckAttributeTarget (Attribute a, object element)\r
555                 {\r
556                         TypeContainer attr = TypeManager.LookupAttr (a.Type);\r
557                         AttributeTargets targets = 0;\r
558 \r
559                         if (attr == null) {\r
560                                 System.Attribute [] attrs = null;\r
561                                 \r
562                                 try {\r
563                                         attrs = System.Attribute.GetCustomAttributes (a.Type);\r
564 \r
565                                 } catch {\r
566                                         Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +\r
567                                                       " (maybe you forgot to set the usage using the" +\r
568                                                       " AttributeUsage attribute ?).");\r
569                                         return false;\r
570                                 }\r
571                                         \r
572                                 foreach (System.Attribute tmp in attrs)\r
573                                         if (tmp is AttributeUsageAttribute) { \r
574                                                 targets = ((AttributeUsageAttribute) tmp).ValidOn;\r
575                                                 break;\r
576                                         }\r
577                         } else\r
578                                 targets = attr.Targets;\r
579 \r
580 \r
581                         if (element is Class) {\r
582                                 if ((targets & AttributeTargets.Class) != 0)\r
583                                         return true;\r
584                                 else\r
585                                         return false;\r
586                                 \r
587                         } else if (element is Struct) {\r
588                                 if ((targets & AttributeTargets.Struct) != 0)\r
589                                         return true;\r
590                                 else\r
591                                         return false;\r
592                         } else if (element is Constructor) {\r
593                                 if ((targets & AttributeTargets.Constructor) != 0)\r
594                                         return true;\r
595                                 else\r
596                                         return false;\r
597                         } else if (element is Delegate) {\r
598                                 if ((targets & AttributeTargets.Delegate) != 0)\r
599                                         return true;\r
600                                 else\r
601                                         return false;\r
602                         } else if (element is Enum) {\r
603                                 if ((targets & AttributeTargets.Enum) != 0)\r
604                                         return true;\r
605                                 else\r
606                                         return false;\r
607                         } else if (element is Event) {\r
608                                 if ((targets & AttributeTargets.Event) != 0)\r
609                                         return true;\r
610                                 else\r
611                                         return false;\r
612                         } else if (element is Field || element is FieldBuilder) {\r
613                                 if ((targets & AttributeTargets.Field) != 0)\r
614                                         return true;\r
615                                 else\r
616                                         return false;\r
617                         } else if (element is Interface) {\r
618                                 if ((targets & AttributeTargets.Interface) != 0)\r
619                                         return true;\r
620                                 else\r
621                                         return false;\r
622                         } else if (element is Method || element is Operator ||\r
623                                    element is Accessor) {\r
624                                 if ((targets & AttributeTargets.Method) != 0)\r
625                                         return true;\r
626                                 else\r
627                                         return false;\r
628                         } else if (element is ParameterBuilder) {\r
629                                 if ((targets & AttributeTargets.Parameter) != 0 ||\r
630                                     (targets & AttributeTargets.ReturnValue) != 0)\r
631                                         return true;\r
632                                 else\r
633                                         return false;\r
634                         } else if (element is Property || element is Indexer ||\r
635                                    element is Accessor) {
636                                 if ((targets & AttributeTargets.Property) != 0)\r
637                                         return true;\r
638                                 else\r
639                                         return false;\r
640                         } else if (element is AssemblyClass){
641                                 if ((targets & AttributeTargets.Assembly) != 0)\r
642                                         return true;\r
643                                 else\r
644                                         return false;\r
645                         } else if (element is ModuleClass){
646                                 if ((targets & AttributeTargets.Module) != 0)
647                                         return true;
648                                 else
649                                         return false;
650                         }\r
651 \r
652                         return false;\r
653                 }\r
654 \r
655                 //\r
656                 // This method should be invoked to pull the IndexerName attribute from an\r
657                 // Indexer if it exists.\r
658                 //\r
659                 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)\r
660                 {\r
661                         if (opt_attrs == null)\r
662                                 return null;\r
663                         if (opt_attrs.AttributeSections == null)\r
664                                 return null;\r
665 \r
666                         foreach (AttributeSection asec in opt_attrs.AttributeSections) {\r
667                                 if (asec.Attributes == null)\r
668                                         continue;\r
669 \r
670                                 foreach (Attribute a in asec.Attributes){\r
671                                         if (a.ResolveType (ec) == null)\r
672                                                 return null;\r
673 \r
674                                         if (a.Type != TypeManager.indexer_name_type)\r
675                                                 continue;\r
676 \r
677                                         //\r
678                                         // So we have found an IndexerName, pull the data out.\r
679                                         //\r
680                                         if (a.Arguments == null || a.Arguments [0] == null){\r
681                                                 Error_AttributeConstructorMismatch (a.Location);\r
682                                                 return null;\r
683                                         }\r
684                                         ArrayList pos_args = (ArrayList) a.Arguments [0];\r
685                                         if (pos_args.Count == 0){\r
686                                                 Error_AttributeConstructorMismatch (a.Location);\r
687                                                 return null;\r
688                                         }\r
689                                         \r
690                                         Argument arg = (Argument) pos_args [0];\r
691                                         if (!arg.Resolve (ec, a.Location))\r
692                                                 return null;\r
693                                         \r
694                                         Expression e = arg.Expr;\r
695                                         if (!(e is StringConstant)){\r
696                                                 Error_AttributeConstructorMismatch (a.Location);\r
697                                                 return null;\r
698                                         }\r
699 \r
700                                         //\r
701                                         // Remove the attribute from the list\r
702                                         //\r
703                                         asec.Attributes.Remove (a);\r
704 \r
705                                         return (((StringConstant) e).Value);\r
706                                 }\r
707                         }\r
708                         return null;\r
709                 }\r
710 \r
711                 //\r
712                 // This pulls the condition name out of a Conditional attribute\r
713                 //\r
714                 public string Conditional_GetConditionName ()\r
715                 {\r
716                         //\r
717                         // So we have a Conditional, pull the data out.\r
718                         //\r
719                         if (Arguments == null || Arguments [0] == null){\r
720                                 Error_AttributeConstructorMismatch (Location);\r
721                                 return null;\r
722                         }\r
723 \r
724                         ArrayList pos_args = (ArrayList) Arguments [0];\r
725                         if (pos_args.Count != 1){\r
726                                 Error_AttributeConstructorMismatch (Location);\r
727                                 return null;\r
728                         }\r
729 \r
730                         Argument arg = (Argument) pos_args [0]; \r
731                         if (!(arg.Expr is StringConstant)){\r
732                                 Error_AttributeConstructorMismatch (Location);\r
733                                 return null;\r
734                         }\r
735 \r
736                         return ((StringConstant) arg.Expr).Value;\r
737                 }\r
738 \r
739                 //\r
740                 // This pulls the obsolete message and error flag out of an Obsolete attribute\r
741                 //\r
742                 public string Obsolete_GetObsoleteMessage (out bool is_error)\r
743                 {\r
744                         is_error = false;\r
745                         //\r
746                         // So we have an Obsolete, pull the data out.\r
747                         //\r
748                         if (Arguments == null || Arguments [0] == null)\r
749                                 return "";\r
750 \r
751                         ArrayList pos_args = (ArrayList) Arguments [0];\r
752                         if (pos_args.Count == 0)\r
753                                 return "";\r
754                         else if (pos_args.Count > 2){\r
755                                 Error_AttributeConstructorMismatch (Location);\r
756                                 return null;\r
757                         }\r
758 \r
759                         Argument arg = (Argument) pos_args [0]; \r
760                         if (!(arg.Expr is StringConstant)){\r
761                                 Error_AttributeConstructorMismatch (Location);\r
762                                 return null;\r
763                         }\r
764 \r
765                         if (pos_args.Count == 2){\r
766                                 Argument arg2 = (Argument) pos_args [1];\r
767                                 if (!(arg2.Expr is BoolConstant)){\r
768                                         Error_AttributeConstructorMismatch (Location);\r
769                                         return null;\r
770                                 }\r
771                                 is_error = ((BoolConstant) arg2.Expr).Value;\r
772                         }\r
773 \r
774                         return ((StringConstant) arg.Expr).Value;\r
775                 }\r
776 \r
777                 static object GetFieldValue (Attribute a, string name)\r
778                 {\r
779                         int i;\r
780                         if (a.field_info_arr == null)\r
781                                 return null;\r
782                         i = 0;\r
783                         foreach (FieldInfo fi in a.field_info_arr) {\r
784                                 if (fi.Name == name)\r
785                                         return a.field_values_arr [i];\r
786                                 i++;\r
787                         }\r
788                         return null;\r
789                 }\r
790 \r
791                 static UnmanagedMarshal GetMarshal (Attribute a)\r
792                 {\r
793                         object o = GetFieldValue (a, "ArraySubType");\r
794                         UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;\r
795                         switch (a.UnmanagedType) {\r
796                         case UnmanagedType.CustomMarshaler:\r
797                                 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",\r
798                                                                        BindingFlags.Static | BindingFlags.Public);\r
799                                 if (define_custom == null)\r
800                                         return null;\r
801 \r
802                                 object [] args = new object [4];\r
803                                 args [0] = GetFieldValue (a, "MarshalTypeRef");\r
804                                 args [1] = GetFieldValue (a, "MarshalCookie");\r
805                                 args [2] = GetFieldValue (a, "MarshalType");\r
806                                 args [3] = Guid.Empty;\r
807                                 return (UnmanagedMarshal) define_custom.Invoke (null, args);\r
808 \r
809                         case UnmanagedType.LPArray:                             \r
810                                 return UnmanagedMarshal.DefineLPArray (array_sub_type);\r
811 \r
812                         case UnmanagedType.SafeArray:\r
813                                 return UnmanagedMarshal.DefineSafeArray (array_sub_type);\r
814 \r
815                         case UnmanagedType.ByValArray:\r
816                                 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));\r
817 \r
818                         case UnmanagedType.ByValTStr:\r
819                                 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));\r
820 \r
821                         default:\r
822                                 return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);\r
823                         }\r
824                 }\r
825 \r
826                 /// <summary>\r
827                 ///   Applies the attributes specified on target 'kind' to the `builder'.\r
828                 /// </summary>\r
829                 public static void ApplyAttributes (EmitContext ec, object builder, object kind,\r
830                                                     Attributes opt_attrs)\r
831                 {\r
832                         Type attr_type = null;\r
833                         \r
834                         if (opt_attrs == null)\r
835                                 return;\r
836                         if (opt_attrs.AttributeSections == null)\r
837                                 return;\r
838 \r
839                         ArrayList emitted_attrs = new ArrayList ();\r
840                         ArrayList emitted_targets = new ArrayList ();\r
841 \r
842                         foreach (AttributeSection asec in opt_attrs.AttributeSections) {\r
843                                 string attr_target = asec.Target;\r
844                                 \r
845                                 if (asec.Attributes == null)\r
846                                         continue;\r
847 \r
848                                 if (attr_target == "return" && !(builder is ParameterBuilder))\r
849                                         continue;\r
850                                 \r
851                                 foreach (Attribute a in asec.Attributes) {\r
852                                         Location loc = a.Location;\r
853                                         CustomAttributeBuilder cb = a.Resolve (ec);\r
854                                         attr_type = a.Type;\r
855 \r
856                                         if (cb == null) \r
857                                                 continue;\r
858                                         \r
859                                         if (!(kind is TypeContainer))\r
860                                                 if (!CheckAttributeTarget (a, kind)) {\r
861                                                         Error_AttributeNotValidForElement (a, loc);\r
862                                                         return;\r
863                                                 }\r
864 \r
865                                         //\r
866                                         // Perform the check for duplicate attributes\r
867                                         //\r
868                                         if (emitted_attrs.Contains (attr_type) &&\r
869                                             emitted_targets.Contains (attr_target) &&\r
870                                             !TypeManager.AreMultipleAllowed (attr_type)) {\r
871                                                 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");\r
872                                                 return;\r
873                                         }\r
874 \r
875                                         if (kind is IAttributeSupport) {
876                                                 if (attr_type == TypeManager.methodimpl_attr_type && a.ImplOptions == MethodImplOptions.InternalCall) {
877                                                         ((MethodBuilder) builder).SetImplementationFlags (MethodImplAttributes.InternalCall | MethodImplAttributes.Runtime);
878                                                 } 
879                                                 else {
880                                                         IAttributeSupport attributeSupport = kind as IAttributeSupport;
881                                                         attributeSupport.SetCustomAttribute (cb);
882                                                 }
883                                         }
884                                         else if (kind is Method || kind is Operator || kind is Accessor) {\r
885                                                 if (attr_type == TypeManager.methodimpl_attr_type) {\r
886                                                         if (a.ImplOptions == MethodImplOptions.InternalCall)\r
887                                                                 ((MethodBuilder) builder).\r
888                                                                 SetImplementationFlags (\r
889                                                                         MethodImplAttributes.InternalCall |\r
890                                                                         MethodImplAttributes.Runtime);\r
891                                                         else\r
892                                                                 ((MethodBuilder) builder).SetCustomAttribute (cb);\r
893                                                 } else if (attr_type != TypeManager.dllimport_type){\r
894                                                         ((MethodBuilder) builder).SetCustomAttribute (cb);\r
895                                                 }\r
896                                         } else if (kind is Constructor) {\r
897                                                 ((ConstructorBuilder) builder).SetCustomAttribute (cb);\r
898                                         } else if (kind is Field) {\r
899                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
900                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
901                                                         if (marshal == null) {\r
902                                                                 Report.Warning (-24, loc,\r
903                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
904                                                                         "Please use the Mono runtime instead.");\r
905                                                         } else {\r
906                                                                 ((FieldBuilder) builder).SetMarshal (marshal);\r
907                                                         }\r
908                                                 } else { \r
909                                                         ((FieldBuilder) builder).SetCustomAttribute (cb);\r
910                                                 }\r
911                                         } else if (kind is Property || kind is Indexer) {\r
912
913                                                 if (builder is PropertyBuilder) 
914                                                 ((PropertyBuilder) builder).SetCustomAttribute (cb);\r
915                                                 //
916                                                 // This is for the case we are setting attributes on
917                                                 // the get and set accessors
918                                                 //
919                                                 else if (builder is MethodBuilder)
920                                                         ((MethodBuilder) builder).SetCustomAttribute (cb);
921                                         } else if (kind is Event) {\r
922                                                 ((MyEventBuilder) builder).SetCustomAttribute (cb);\r
923                                         } else if (kind is ParameterBuilder) {\r
924 \r
925                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
926                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
927                                                         if (marshal == null) {\r
928                                                                 Report.Warning (-24, loc,\r
929                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
930                                                                         "Please use the Mono runtime instead.");\r
931                                                         } else {\r
932                                                                 ((ParameterBuilder) builder).SetMarshal (marshal);\r
933                                                         }\r
934                                                 } else { \r
935 \r
936                                                         try {\r
937                                                                 ((ParameterBuilder) builder).SetCustomAttribute (cb);\r
938                                                         } catch (System.ArgumentException) {\r
939                                                                 Report.Warning (-24, loc,\r
940                                                                                 "The Microsoft Runtime cannot set attributes \n" +\r
941                                                                                 "on the return type of a method. Please use the \n" +\r
942                                                                                 "Mono runtime instead.");\r
943                                                         }\r
944 \r
945                                                 }\r
946                                         } else if (kind is Enum) {\r
947                                                 ((TypeBuilder) builder).SetCustomAttribute (cb); \r
948 \r
949                                         } else if (kind is TypeContainer) {\r
950                                                 TypeContainer tc = (TypeContainer) kind;\r
951                                                 \r
952                                                 if (a.UsageAttr) {\r
953                                                         tc.Targets = a.Targets;\r
954                                                         tc.AllowMultiple = a.AllowMultiple;\r
955                                                         tc.Inherited = a.Inherited;\r
956 \r
957                                                         TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,\r
958                                                                                                     tc.AllowMultiple);\r
959                                                         \r
960                                                 } else if (attr_type == TypeManager.default_member_type) {\r
961                                                         if (tc.Indexers != null) {\r
962                                                                 Report.Error (646, loc,\r
963                                                                       "Cannot specify the DefaultMember attribute on" +\r
964                                                                       " a type containing an indexer");\r
965                                                                 return;\r
966                                                         }\r
967 \r
968                                                 } else {\r
969                                                         if (!CheckAttributeTarget (a, kind)) {\r
970                                                                 Error_AttributeNotValidForElement (a, loc);\r
971                                                                 return;\r
972                                                         }\r
973                                                 }\r
974 \r
975                                                 try {\r
976                                                         ((TypeBuilder) builder).SetCustomAttribute (cb);\r
977                                                 } catch (System.ArgumentException) {\r
978                                                         Report.Warning (\r
979                                                                 -21, loc,\r
980                                                 "The CharSet named property on StructLayout\n"+\r
981                                                 "\tdoes not work correctly on Microsoft.NET\n"+\r
982                                                 "\tYou might want to remove the CharSet declaration\n"+\r
983                                                 "\tor compile using the Mono runtime instead of the\n"+\r
984                                                 "\tMicrosoft .NET runtime");\r
985                                                 }\r
986                                         } else if (kind is Delegate){\r
987                                                 if (!CheckAttributeTarget (a, kind)) {\r
988                                                         Error_AttributeNotValidForElement (a, loc);\r
989                                                         return;\r
990                                                 }\r
991                                                 try {\r
992                                                         ((TypeBuilder) builder).SetCustomAttribute (cb);\r
993                                                 } catch (System.ArgumentException) {\r
994                                                         Report.Warning (\r
995                                                                 -21, loc,\r
996                                                 "The CharSet named property on StructLayout\n"+\r
997                                                 "\tdoes not work correctly on Microsoft.NET\n"+\r
998                                                 "\tYou might want to remove the CharSet declaration\n"+\r
999                                                 "\tor compile using the Mono runtime instead of the\n"+\r
1000                                                 "\tMicrosoft .NET runtime");\r
1001                                                 }\r
1002                                         } else if (kind is Interface) {\r
1003                                                 Interface iface = (Interface) kind;\r
1004 \r
1005                                                 if ((attr_type == TypeManager.default_member_type) &&\r
1006                                                     (iface.Indexers != null)) {\r
1007                                                         Report.Error (\r
1008                                                                 646, loc,\r
1009                                                                 "Cannot specify the DefaultMember attribute on" +\r
1010                                                                 " a type containing an indexer");\r
1011                                                         return;\r
1012                                                 }\r
1013 \r
1014                                                 if (!CheckAttributeTarget (a, kind)) {\r
1015                                                         Error_AttributeNotValidForElement (a, loc);\r
1016                                                         return;\r
1017                                                 }\r
1018 \r
1019                                                 ((TypeBuilder) builder).SetCustomAttribute (cb);\r
1020                                         } else if (kind is AssemblyBuilder){\r
1021                                                 ((AssemblyBuilder) builder).SetCustomAttribute (cb);\r
1022                                         } else if (kind is ModuleBuilder) {\r
1023                                                 ((ModuleBuilder) builder).SetCustomAttribute (cb);\r
1024                                         } else if (kind is FieldBuilder) {\r
1025                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
1026                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
1027                                                         if (marshal == null) {\r
1028                                                                 Report.Warning (-24, loc,\r
1029                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
1030                                                                         "Please use the Mono runtime instead.");\r
1031                                                         } else {\r
1032                                                                 ((ParameterBuilder) builder).SetMarshal (marshal);\r
1033                                                         }\r
1034                                                 } else { \r
1035                                                         ((FieldBuilder) builder).SetCustomAttribute (cb);\r
1036                                                 }\r
1037                                         } else\r
1038                                                 throw new Exception ("Unknown kind: " + kind);\r
1039 \r
1040                                         //\r
1041                                         // Once an attribute type has been emitted once we\r
1042                                         // keep track of the info to prevent multiple occurences\r
1043                                         // for attributes which do not explicitly allow it\r
1044                                         //\r
1045                                         if (!emitted_attrs.Contains (attr_type))\r
1046                                                 emitted_attrs.Add (attr_type);\r
1047 \r
1048                                         //\r
1049                                         // We keep of this target-wise and so emitted targets\r
1050                                         // are tracked too\r
1051                                         //\r
1052                                         if (!emitted_targets.Contains (attr_target))\r
1053                                                 emitted_targets.Add (attr_target);\r
1054                                 }\r
1055                                 \r
1056                                 \r
1057                         }\r
1058                 }\r
1059 \r
1060                 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,\r
1061                                                           MethodAttributes flags, Type ret_type, Type [] param_types)\r
1062                 {\r
1063                         //\r
1064                         // We extract from the attribute the information we need \r
1065                         //\r
1066 \r
1067                         if (Arguments == null) {\r
1068                                 Console.WriteLine ("Internal error : this is not supposed to happen !");\r
1069                                 return null;\r
1070                         }\r
1071 \r
1072                         Type = CheckAttributeType (ec);\r
1073                         if (Type == null)\r
1074                                 return null;\r
1075                         \r
1076                         ArrayList named_args = new ArrayList ();\r
1077                         \r
1078                         ArrayList pos_args = (ArrayList) Arguments [0];\r
1079                         if (Arguments.Count > 1)\r
1080                                 named_args = (ArrayList) Arguments [1];\r
1081                         \r
1082 \r
1083                         string dll_name = null;\r
1084                         \r
1085                         Argument tmp = (Argument) pos_args [0];\r
1086 \r
1087                         if (!tmp.Resolve (ec, Location))\r
1088                                 return null;\r
1089                         \r
1090                         if (tmp.Expr is Constant)\r
1091                                 dll_name = (string) ((Constant) tmp.Expr).GetValue ();\r
1092                         else { \r
1093                                 Error_AttributeArgumentNotValid (Location);\r
1094                                 return null;\r
1095                         }\r
1096 \r
1097                         // Now we process the named arguments\r
1098                         CallingConvention cc = CallingConvention.Winapi;\r
1099                         CharSet charset = CharSet.Ansi;\r
1100                         bool preserve_sig = true;\r
1101 #if FIXME\r
1102                         bool exact_spelling = false;\r
1103 #endif\r
1104                         bool set_last_err = false;\r
1105                         string entry_point = null;\r
1106 \r
1107                         for (int i = 0; i < named_args.Count; i++) {\r
1108 \r
1109                                 DictionaryEntry de = (DictionaryEntry) named_args [i];\r
1110 \r
1111                                 string member_name = (string) de.Key;\r
1112                                 Argument a  = (Argument) de.Value;\r
1113 \r
1114                                 if (!a.Resolve (ec, Location))\r
1115                                         return null;\r
1116 \r
1117                                 Expression member = Expression.MemberLookup (\r
1118                                         ec, Type, member_name, \r
1119                                         MemberTypes.Field | MemberTypes.Property,\r
1120                                         BindingFlags.Public | BindingFlags.Instance,\r
1121                                         Location);\r
1122 \r
1123                                 if (member == null || !(member is FieldExpr)) {\r
1124                                         Error_InvalidNamedArgument (member_name);\r
1125                                         return null;\r
1126                                 }\r
1127 \r
1128                                 if (member is FieldExpr) {\r
1129                                         FieldExpr fe = (FieldExpr) member;\r
1130                                         FieldInfo fi = fe.FieldInfo;\r
1131 \r
1132                                         if (fi.IsInitOnly) {\r
1133                                                 Error_InvalidNamedArgument (member_name);\r
1134                                                 return null;\r
1135                                         }\r
1136 \r
1137                                         if (a.Expr is Constant) {\r
1138                                                 Constant c = (Constant) a.Expr;\r
1139                                                 \r
1140                                                 if (member_name == "CallingConvention")\r
1141                                                         cc = (CallingConvention) c.GetValue ();\r
1142                                                 else if (member_name == "CharSet")\r
1143                                                         charset = (CharSet) c.GetValue ();\r
1144                                                 else if (member_name == "EntryPoint")\r
1145                                                         entry_point = (string) c.GetValue ();\r
1146                                                 else if (member_name == "SetLastError")\r
1147                                                         set_last_err = (bool) c.GetValue ();\r
1148 #if FIXME\r
1149                                                 else if (member_name == "ExactSpelling")\r
1150                                                         exact_spelling = (bool) c.GetValue ();\r
1151 #endif\r
1152                                                 else if (member_name == "PreserveSig")\r
1153                                                         preserve_sig = (bool) c.GetValue ();\r
1154                                         } else { \r
1155                                                 Error_AttributeArgumentNotValid (Location);\r
1156                                                 return null;\r
1157                                         }\r
1158                                         \r
1159                                 }\r
1160                         }\r
1161 \r
1162                         if (entry_point == null)\r
1163                                 entry_point = name;\r
1164                         if (set_last_err)\r
1165                                 charset = (CharSet)((int)charset | 0x40);\r
1166                         \r
1167                         MethodBuilder mb = builder.DefinePInvokeMethod (\r
1168                                 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,\r
1169                                 CallingConventions.Standard,\r
1170                                 ret_type,\r
1171                                 param_types,\r
1172                                 cc,\r
1173                                 charset);\r
1174 \r
1175                         if (preserve_sig)\r
1176                                 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);\r
1177                         \r
1178                         return mb;\r
1179                 }\r
1180                 \r
1181         }\r
1182         \r
1183         public class AttributeSection {\r
1184                 public readonly string    Target;\r
1185                 public readonly ArrayList Attributes;\r
1186                 \r
1187                 public AttributeSection (string target, ArrayList attrs)\r
1188                 {\r
1189                         Target = target;\r
1190                         Attributes = attrs;\r
1191                 }\r
1192                 \r
1193         }\r
1194 \r
1195         public class Attributes {\r
1196                 public ArrayList AttributeSections;\r
1197 \r
1198                 public Attributes (AttributeSection a)\r
1199                 {\r
1200                         AttributeSections = new ArrayList ();\r
1201                         AttributeSections.Add (a);\r
1202 \r
1203                 }\r
1204 \r
1205                 public void AddAttributeSection (AttributeSection a)\r
1206                 {\r
1207                         if (a != null && !AttributeSections.Contains (a))\r
1208                                 AttributeSections.Add (a);\r
1209                 }\r
1210 \r
1211                 public bool Contains (Type t)\r
1212                 {\r
1213                         foreach (AttributeSection attr_section in AttributeSections){\r
1214                                 foreach (Attribute a in attr_section.Attributes){\r
1215                                         if (a.Type == t)\r
1216                                                 return true;\r
1217                                 }\r
1218                         }\r
1219                         \r
1220                         return false;\r
1221                 }\r
1222         }\r
1223
1224         public interface IAttributeSupport {
1225                 void SetCustomAttribute (CustomAttributeBuilder customBuilder);
1226         }
1227 }\r