new tests
[mono.git] / mcs / mbas / genericparser.cs
1 //\r
2 // GenericParser.cs: The Base Parser for the Mono compilers\r
3 //\r
4 // Author: A Rafael D Teixeira (rafaelteixeirabr@hotmail.com)\r
5 //\r
6 // Licensed under the terms of the GNU GPL\r
7 //\r
8 // Copyright (C) 2001 Ximian, Inc.\r
9 //\r
10 \r
11 namespace Mono.Languages\r
12 {\r
13         using System;\r
14         using System.Reflection;\r
15         using System.Collections;\r
16         using System.IO;
17         using System.Text;\r
18         using Mono.MonoBASIC;\r
19 \r
20         /// <summary>\r
21         /// Base class to support multiple Jay generated parsers\r
22         /// </summary>\r
23         public abstract class GenericParser\r
24         {\r
25                 // ---------------------------------------------------\r
26                 // Class state\r
27 \r
28                 // Count of errors found while parsing\r
29                 static protected int global_errors;\r
30 \r
31                 // Maps extensions to specific parsers\r
32                 static private Hashtable mapOfParsers;\r
33 \r
34                 // Maps extensions to specific parsers\r
35                 static private GenericParser defaultParser = null;\r
36 \r
37                 // Indicates if parsing should be verbose\r
38                 static public int yacc_verbose_flag = 0;\r
39 \r
40                 // Context to use\r
41                 static public ArrayList defines;\r
42 \r
43                 // ---------------------------------------------------\r
44                 // Instance state\r
45 \r
46                 // Name of the file we are parsing\r
47                 protected string name;\r
48 \r
49                 // Input stream to parse from.\r
50                 protected System.IO.TextReader input;\r
51 \r
52                 // Current namespace definition\r
53                 protected Namespace     current_namespace;\r
54 \r
55                 // Current typecontainer definition\r
56                 protected TypeContainer current_container;\r
57                 \r
58                 // ---------------------------------------------------\r
59                 // What the descendants MUST reimplement\r
60 \r
61                 /// <summary>\r
62                 /// Parses the current "input"\r
63                 /// </summary>\r
64                 protected abstract int parse();\r
65 \r
66                 /// <summary>\r
67                 /// Lists the extensions this parser can handle\r
68                 /// </summary>\r
69                 public abstract string[] extensions();\r
70                 /* {\r
71                         string [] list = { ".cs" };\r
72                         return list;\r
73                 } */\r
74 \r
75                 // ---------------------------------------------------\r
76                 // What the descendants DONT HAVE to reimplement\r
77 \r
78                 /// <summary>\r
79                 /// Initializes this parser from a file and parses it\r
80                 /// </summary>\r
81                 /// <param name="fileName">Name of the file to be parsed</param>\r
82                 public int ParseFile(string fileName)\r
83                 {\r
84                         // file exceptions must be caught by caller\r
85 \r
86                         global_errors = 0;\r
87                         name = fileName;\r
88                         // TODO: Encoding switching as needed\r
89                         //   We are here forcing StreamReader to assume current system codepage,\r
90                         //   because normally it defaults to UTF-8\r
91                         input = new StreamReader(fileName, System.Text.Encoding.Default); \r
92                         //rc = context;\r
93                         return parse();\r
94                 }\r
95 \r
96                 /// <summary>\r
97                 /// Initializes this parser from a file and parses it\r
98                 /// </summary>\r
99                 /// <param name="fileName">Name of the file to be parsed</param>\r
100                 /// <param name="encoding">Specific encoding to use in parsing</param>\r
101                 public int ParseFile(string fileName, Encoding encoding)\r
102                 {\r
103                         // file exceptions must be caught by caller\r
104 \r
105                         global_errors = 0;\r
106                         name = fileName;\r
107                         // TODO: Encoding switching as needed\r
108                         //   We are here forcing StreamReader to assume an specific encoding\r
109                         input = new StreamReader(fileName, encoding); \r
110                         //rc = context;\r
111                         return parse();\r
112                 }\r
113 \r
114                 /// <summary>\r
115                 /// Initializes this parser from a string and parses it\r
116                 /// </summary>\r
117                 /// <param name="source">String to be parsed</param>\r
118                 /// <param name="sourceName">Name of the source to be parsed (just for error reporting)</param>\r
119                 public int ParseString(string source, string sourceName)\r
120                 {\r
121                         global_errors = 0;\r
122                         name = sourceName;\r
123                         input = new StringReader(source);\r
124                         //rc = context;\r
125                         return parse();\r
126                 }\r
127 \r
128                 // ---------------------------------------------------\r
129                 // Class methods\r
130 \r
131                 static private void MapParsers()\r
132                 {\r
133                         mapOfParsers = new Hashtable();\r
134 \r
135                         Assembly thisAssembly = Assembly.GetExecutingAssembly();\r
136                         foreach(Type type in thisAssembly.GetTypes())\r
137                         {\r
138                                 if (type.BaseType != null)\r
139                                         if (type.BaseType.FullName == "Mono.Languages.GenericParser")\r
140                                         {\r
141                                                 GenericParser parser = (GenericParser)Activator.CreateInstance(type);\r
142                                                 foreach(string fileExtension in parser.extensions())\r
143                                                 {                                                                                               \r
144                                                         string theFileExtension = fileExtension.ToLower();\r
145                                                         if (mapOfParsers.Contains(theFileExtension))\r
146                                                                 Console.WriteLine("[TRACE] " + type.FullName + " can't try to parse '" + theFileExtension + "' files too");\r
147                                                         else\r
148                                                                 mapOfParsers.Add(theFileExtension, parser);\r
149                                                 }\r
150                                                 object[] attribs = type.GetCustomAttributes(typeof(DefaultParserAttribute), false);\r
151                                                 if (attribs != null && attribs.Length > 0)\r
152                                                 {\r
153                                                         if (defaultParser == null)\r
154                                                                 defaultParser = parser;\r
155                                                         else\r
156                                                                 Console.WriteLine("[TRACE] " + type.FullName + " can't be another default parser");                                                             \r
157                                                 }\r
158                                         }\r
159                         }\r
160                 }\r
161 \r
162                 /// <summary>\r
163                 /// Find the descendant parser that knows how to parse the specified file\r
164                 /// based on the file extension, or the default parser otherwise, if available\r
165                 /// </summary>\r
166                 /// <param name="fileName">Name of the file to be parsed</param>\r
167                 public static GenericParser GetSpecificParserFor(string fileName)\r
168                 {\r
169                         int i;\r
170                         GenericParser chosenParser = null;\r
171                         \r
172                         if (mapOfParsers == null)\r
173                                 MapParsers();\r
174                         \r
175                         if ((i = fileName.LastIndexOf(".")) > 0)\r
176                         {\r
177                                 string fileExtension = fileName.Substring(i).ToLower();\r
178                                 chosenParser = (GenericParser)mapOfParsers[fileExtension];\r
179                         }\r
180                         \r
181                         if (chosenParser != null)                       \r
182                                 return chosenParser;\r
183                                 \r
184                         return defaultParser;\r
185                 }\r
186 \r
187
188                 [Obsolete]              \r
189                 public static int Tokenize(string fileName)\r
190                 {\r
191                         return 1;\r
192                 }\r
193 \r
194 \r
195                 /// <summary>\r
196                 /// Find the descendant parser that knows how to parse the specified file\r
197                 /// based on the files extension, and parses it using the chosen parser\r
198                 /// </summary>\r
199                 /// <param name="fileName">Name of the file to be parsed</param>
200                 [Obsolete]\r
201                 public static int Parse(string fileName)\r
202                 {
203                         return Parse(fileName, null);
204                 }
205                 \r
206                 /// <summary>\r
207                 /// Find the descendant parser that knows how to parse the specified file\r
208                 /// based on the files extension, and parses it using the chosen parser\r
209                 /// </summary>\r
210                 /// <param name="fileName">Name of the file to be parsed</param>\r
211                 /// <param name="encoding">Encoding of the file to be parsed</param>\r
212                 public static int Parse(string fileName, Encoding encoding)\r
213                 {\r
214                         int errors;\r
215                         GenericParser parser = GetSpecificParserFor(fileName);\r
216                                                 \r
217                         if (parser == null)\r
218                         {\r
219                                 Console.WriteLine("Do not know how to compile " + fileName);\r
220                                 return 1;\r
221                         }\r
222                         
223                         if (encoding == null)
224                                 encoding = Encoding.Default;
225                                 \r
226                         try \r
227                         {\r
228                                 errors = parser.ParseFile(fileName, encoding);\r
229                         } \r
230                         catch (FileNotFoundException)\r
231                         {\r
232                                 Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");\r
233                                 return 1;\r
234                         }\r
235                         catch (DirectoryNotFoundException)\r
236                         {\r
237                                 Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");\r
238                                 return 1;\r
239                         }                       \r
240                         catch (Exception ex)\r
241                         {\r
242                                 Console.WriteLine (ex);\r
243                                 Console.WriteLine ("Compilation aborted");\r
244                                 return 1;\r
245                         }\r
246                         \r
247                         return errors;\r
248                 }\r
249 \r
250                 // <summary>\r
251                 //   Given the @class_name name, it creates a fully qualified name\r
252                 //   based on the containing declaration space\r
253                 // </summary>\r
254                 protected string MakeName(string class_name)\r
255                 {\r
256                         string ns = current_namespace.Name;\r
257                         string container_name = current_container.Name;\r
258 \r
259                         if (container_name == "")\r
260                         {\r
261                                 if (ns != "")\r
262                                         return ns + "." + class_name;\r
263                                 else\r
264                                         return class_name;\r
265                         } \r
266                         else\r
267                                 return container_name + "." + class_name;\r
268                 }\r
269 \r
270                 // <summary>\r
271                 //   Used to report back to the user the result of a declaration\r
272                 //   in the current declaration space\r
273                 // </summary>\r
274                 protected void CheckDef (AdditionResult result, string name, Location l)\r
275                 {\r
276                         if (result == AdditionResult.Success)\r
277                                 return;\r
278 \r
279                         switch (result)\r
280                         {\r
281                                 case AdditionResult.NameExists:\r
282                                         Report.Error (102, l, "The container '" + current_container.Name + \r
283                                                 "' already contains a definition for '"+\r
284                                                 name + "'");\r
285                                         break;\r
286 \r
287 \r
288                                         //\r
289                                         // This is handled only for static Constructors, because\r
290                                         // in reality we handle these by the semantic analysis later\r
291                                         //\r
292                                 case AdditionResult.MethodExists:\r
293                                         Report.Error (\r
294                                                 111, l, "Class `"+current_container.Name+\r
295                                                 "' already defines a member called '" + \r
296                                                 name + "' with the same parameter types (more than one default constructor)");\r
297                                         break;\r
298 \r
299                                 case AdditionResult.EnclosingClash:\r
300                                         Report.Error (542, l, "Member names cannot be the same as their enclosing type");\r
301                                         break;\r
302                 \r
303                                 case AdditionResult.NotAConstructor:\r
304                                         Report.Error (1520, l, "Class, struct, or interface method must have a return type");\r
305                                         break;\r
306                         }\r
307                 }\r
308 \r
309                 // <summary>\r
310                 //   Used to report back to the user the result of a declaration\r
311                 //   in the current declaration space\r
312                 // </summary>\r
313                 protected void CheckDef (bool result, string name, Location l)\r
314                 {\r
315                         if (result)\r
316                                 return;\r
317                         CheckDef (AdditionResult.NameExists, name, l);\r
318                 }\r
319 \r
320 \r
321                 // ---------------------------------------------------\r
322                 // Constructors\r
323 \r
324                 public GenericParser()\r
325                 {\r
326                         // DO NOTHING\r
327                 }\r
328 \r
329         }\r
330 }