merge from trunk revisions 58933, 58935, 58936
[mono.git] / mcs / class / Microsoft.JScript / Microsoft.JScript / SemanticAnalizer.cs
1 //
2 // SemanticAnalyser.cs: Initiate the type check and identification phases.
3 //
4 // Author:
5 //      Cesar Lopez Nataren
6 //
7 // (C) 2003, 2004 Cesar Lopez Nataren, <cesar@ciencias.unam.mx>
8 // (C) 2005, Novell Inc.
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Reflection;
34 using System.Collections;
35
36 namespace Microsoft.JScript {
37
38         internal class SemanticAnalyser {
39
40                 internal static bool print = true;
41                 internal static bool allow_member_expr_as_function_name;
42                 static Environment env;
43                 static IdentificationTable label_set;
44
45                 private static Hashtable obj_ctrs;
46                 private static Hashtable prototypes;
47                 internal static Hashtable methods_with_eval = new Hashtable ();
48                 internal static Hashtable methods_with_outter_scope_refs = new Hashtable ();
49                 internal static Hashtable methods_with_vars_used_nested = new Hashtable ();
50                 internal static Environment Ocurrences = new Environment ();
51
52                 //
53                 // Type to GlobalObject
54                 //
55                 private static Type global_obj = typeof (GlobalObject);
56
57                 internal static bool NoFast = true;
58                 private static Assembly [] assemblies;
59
60                 private static readonly string global_namespace = String.Empty;
61                 internal static string GlobalNamespace {
62                         get { return global_namespace; }
63                 }
64
65                 static SemanticAnalyser ()
66                 {
67                         label_set = new IdentificationTable ();
68                         
69                         obj_ctrs = new Hashtable ();
70                         obj_ctrs.Add ("Array", typeof (ArrayConstructor));
71                         obj_ctrs.Add ("Boolean", typeof (BooleanConstructor));
72                         obj_ctrs.Add ("Date", typeof (DateConstructor));
73                         obj_ctrs.Add ("Function", typeof (FunctionConstructor));
74                         obj_ctrs.Add ("Math", typeof (MathObject));
75                         obj_ctrs.Add ("Number", typeof (NumberConstructor));
76                         obj_ctrs.Add ("Object", typeof (ObjectConstructor));
77                         obj_ctrs.Add ("String", typeof (StringConstructor));
78                         obj_ctrs.Add ("RegExp", typeof (RegExpConstructor));
79
80                         prototypes = new Hashtable ();
81                         // Constructors
82                         prototypes.Add (typeof (FunctionConstructor), typeof (FunctionPrototype));
83                         prototypes.Add (typeof (ArrayConstructor), typeof (FunctionPrototype));
84                         prototypes.Add (typeof (StringConstructor), typeof (FunctionPrototype));
85                         prototypes.Add (typeof (BooleanConstructor), typeof (FunctionPrototype));
86                         prototypes.Add (typeof (NumberConstructor), typeof (FunctionPrototype));
87                         prototypes.Add (typeof (DateConstructor), typeof (FunctionPrototype));
88                         prototypes.Add (typeof (RegExpConstructor), typeof (FunctionPrototype));
89                         prototypes.Add (typeof (ObjectConstructor), typeof (FunctionPrototype));
90                         prototypes.Add (typeof (ErrorConstructor), typeof (FunctionPrototype));
91                         // Prototypes
92                         prototypes.Add (typeof (FunctionPrototype), typeof (ObjectPrototype));
93                         prototypes.Add (typeof (ArrayPrototype), typeof (ObjectPrototype));
94                         prototypes.Add (typeof (StringPrototype), typeof (ObjectPrototype));
95                         prototypes.Add (typeof (BooleanPrototype), typeof (ObjectPrototype));
96                         prototypes.Add (typeof (NumberPrototype), typeof (ObjectPrototype));
97                         prototypes.Add (typeof (DatePrototype), typeof (ObjectPrototype));
98                         prototypes.Add (typeof (RegExpPrototype), typeof (ObjectPrototype));
99                         prototypes.Add (typeof (ErrorPrototype), typeof (ObjectPrototype));
100                         // Regular objects
101                         prototypes.Add (typeof (object), typeof (ObjectPrototype));
102                         prototypes.Add (typeof (FunctionObject), typeof (FunctionPrototype));
103                         prototypes.Add (typeof (ScriptFunction), typeof (FunctionPrototype));
104                         prototypes.Add (typeof (Closure), typeof (FunctionPrototype));
105                         prototypes.Add (typeof (ArrayObject), typeof (ArrayPrototype));
106                         prototypes.Add (typeof (StringObject), typeof (StringPrototype));
107                         prototypes.Add (typeof (BooleanObject), typeof (BooleanPrototype));
108                         prototypes.Add (typeof (NumberObject), typeof (NumberPrototype));
109                         prototypes.Add (typeof (DateObject), typeof (DatePrototype));
110                         prototypes.Add (typeof (RegExpObject), typeof (RegExpPrototype));
111                         prototypes.Add (typeof (RegExpMatch), typeof (ArrayPrototype));
112                         prototypes.Add (typeof (ObjectPrototype), typeof (ObjectPrototype));
113                         prototypes.Add (typeof (ErrorObject), typeof (ErrorPrototype));
114                         prototypes.Add (typeof (EvalErrorObject), typeof (ErrorPrototype));
115                         prototypes.Add (typeof (RangeErrorObject), typeof (ErrorPrototype));
116                         prototypes.Add (typeof (SyntaxErrorObject), typeof (ErrorPrototype));
117                         prototypes.Add (typeof (TypeErrorObject), typeof (ErrorPrototype));
118                         prototypes.Add (typeof (URIErrorObject), typeof (ErrorPrototype));
119
120
121                         // literals, used when accessing a method from the prototype
122                         // through the literal
123                         prototypes.Add (typeof (ArrayLiteral), typeof (ArrayPrototype));
124                         prototypes.Add (typeof (StringLiteral), typeof (StringPrototype));
125                         prototypes.Add (typeof (BooleanConstant), typeof (BooleanPrototype));
126
127                         Type number_prototype = typeof (NumberPrototype);
128                         prototypes.Add (typeof (ByteConstant), number_prototype);
129                         prototypes.Add (typeof (ShortConstant), number_prototype);
130                         prototypes.Add (typeof (IntConstant), number_prototype);
131                         prototypes.Add (typeof (LongConstant), number_prototype);
132                         prototypes.Add (typeof (FloatConstant), number_prototype);
133                         prototypes.Add (typeof (DoubleConstant), number_prototype);
134                 }
135
136                 internal static string ImplementationName (string name)
137                 {
138                         int i = name.LastIndexOf ('_');
139                         return name.Substring (i + 1);
140                 }
141
142                 internal static bool Run (ScriptBlock [] blocks, Assembly [] ref_items)
143                 {
144                         assemblies = ref_items;
145                         ComputeNamespaces ();
146                         env = new Environment (blocks);
147                         bool r = true;
148
149                         foreach (ScriptBlock script_block in blocks)
150                                 ((ICanModifyContext) script_block).PopulateContext (env, String.Empty);
151
152                         foreach (ScriptBlock script_block in blocks)
153                                 r &= script_block.Resolve (env);
154
155                         return r;
156                 }
157
158                 static int anon_method_counter = -1;
159                 internal static string NextAnonymousMethod {
160                         get { 
161                                 anon_method_counter++;
162                                 return "anonymous " + anon_method_counter; 
163                         }
164                 }
165
166                 static int anon_regExp_counter = -1;
167                 internal static string NextAnonymousRegExpObj {
168                         get {
169                                 anon_regExp_counter++;
170                                 return "regexp " + anon_regExp_counter;
171                         }
172                 }
173                 
174                 internal static string CurrentAnonymousMethod {
175                         get { return "anonymous " + anon_method_counter; }
176                 }
177
178                 internal static void AddLabel (string name, AST binding)
179                 {
180                         label_set.Enter (Symbol.CreateSymbol (name), binding);
181                 }
182                 
183                 internal static bool ContainsLabel (string name)
184                 {
185                         object r = label_set.Get (Symbol.CreateSymbol (name));
186                         return r != null;
187                 }
188
189                 internal static object GetLabel (string name) 
190                 {
191                         return label_set.Get (Symbol.CreateSymbol (name));
192                 }
193
194                 internal static void RemoveLabel (string name)
195                 {
196                         label_set.Remove (Symbol.CreateSymbol (name));
197                 }
198
199
200                 internal static void assert_type (object thisObj, Type expType)
201                 {
202                         if (thisObj == null || (thisObj.GetType () != expType && !thisObj.GetType ().IsSubclassOf (expType)))
203                                 throw new Exception ("Type error");
204                 }
205
206                 internal static bool contains (Type target_type, string name, BindingFlags flags)
207                 {
208                         MemberInfo [] type_props = target_type.GetMembers (flags);
209                         foreach (MemberInfo mi in type_props)
210                                 if (mi.Name == name)
211                                         return true;
212                         return false;
213                 }
214
215                 internal static bool is_js_object (string name)
216                 {                       
217                         return contains (global_obj, name, BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
218                 }
219                 
220                 //
221                 // We assume type is a valid native object
222                 // type. Search for method name.
223                 //
224                 internal static bool object_contains (Type type, string name)
225                 {
226                         return contains (type, name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
227                 }
228
229                 internal static Type map_to_ctr (string type_name)
230                 {
231                         return (Type) obj_ctrs [type_name];
232                 }
233
234                 internal static MemberInfo get_member (AST left, AST right)
235                 {
236                         bool right_is_identifier = false;
237                         
238                         if (left != null && right != null) {
239                                 right_is_identifier = right is Identifier;
240
241                                 Type target_type = null;
242                                 string prop_name = string.Empty;
243                                 string obj = string.Empty;
244                                         
245                                 if (left is Identifier && right_is_identifier) {
246                                         obj =  ((Identifier) left).name.Value;
247                                         prop_name = ((Identifier) right).name.Value;
248                                         target_type = SemanticAnalyser.map_to_ctr (obj);
249                                 } else if (left is ICanLookupPrototype && right_is_identifier) {
250                                         prop_name = ((Identifier) right).name.Value;
251                                         target_type = SemanticAnalyser.map_to_prototype (left);
252                                 }
253                                 if (target_type != null && prop_name != string.Empty)
254                                         return Find (target_type, prop_name);
255                         }
256                         return null;
257                 }
258
259                 internal static MemberInfo Find (Type type, string propertyName)
260                 {
261                         MemberInfo [] members = type.GetMember (propertyName);
262                         if (members != null && members.Length > 0)
263                                 return members [0];
264                         return null;
265                 }
266
267                 internal static Type map_to_prototype (object jsObj)
268                 {
269                         if (jsObj == null)
270                                 throw new Exception ("jsObj can't be null");
271                         return (Type) prototypes [jsObj.GetType ()];
272                 }
273
274                 internal static void AddMethodWithEval (string name)
275                 {
276                         object contained = methods_with_eval [name];
277                         if (contained == null)
278                                 methods_with_eval.Add (name, true);
279                 }
280
281                 internal static bool MethodContainsEval (string name)
282                 {
283                         object val = methods_with_eval [name];
284                         return val != null;
285                 }
286
287                 internal static void AddMethodReferenceOutterScopeVar (string name, VariableDeclaration decl)
288                 {
289                         object contained = methods_with_outter_scope_refs [name];
290                         if (contained == null)
291                                 methods_with_outter_scope_refs.Add (name, decl);
292                 }
293
294                 internal static void AddMethodVarsUsedNested (string name, VariableDeclaration decl)
295                 {
296                         object contained = methods_with_vars_used_nested [name];
297                         if (contained == null)
298                                 methods_with_vars_used_nested.Add (name, decl);
299                 }
300
301                 internal static bool MethodReferenceOutterScopeVar (string name)
302                 {
303                         return OutterScopeVar (name) != null;
304                 }
305
306                 internal static VariableDeclaration OutterScopeVar (string name)
307                 {
308                         return (VariableDeclaration) methods_with_outter_scope_refs [name];
309                 }
310
311                 internal static bool MethodVarsUsedNested (string name)
312                 {
313                         bool r = VarUsedNested (name) != null;
314                         return r;
315                 }
316
317                 internal static VariableDeclaration VarUsedNested (string name)
318                 {
319                         return (VariableDeclaration) methods_with_vars_used_nested [name];
320                 }
321
322                 internal static Type IsLiteral (AST ast)
323                 {
324                         if (ast != null) {
325                                 Type type = ast.GetType ();
326                                 // FIXME: Add test for other literals (exclude StringLiteral)
327                                 if (type == typeof (ArrayLiteral))
328                                         return type;
329                         }
330                         return null;
331                 }
332
333                 internal static bool IsNumericConstant (object o)
334                 {
335                         return o is ByteConstant || o is ShortConstant ||
336                                 o is IntConstant || o is LongConstant ||
337                                 o is FloatConstant || o is DoubleConstant;
338                 }
339
340                 internal static bool NeedsToBoolean (AST ast)
341                 {
342                         if (ast is BooleanConstant || ast is StrictEquality)
343                                 return false;
344                         else if (ast is Expression)
345                                 return NeedsToBoolean (((Expression) ast).Last);
346                         else if (ast is Unary) {
347                                 Unary unary = (Unary) ast;
348                                 if (unary.oper != JSToken.LogicalNot)
349                                         return true;
350                                 return false;
351                         } else if (ast is Call || ast is Identifier)
352                                 return true;
353                         else {
354                                 Console.WriteLine ("ast.LineNumber = {0}", ast.Location.LineNumber);
355                                 throw new NotImplementedException ();
356                         }
357                 }
358
359                 internal static bool Needs (JSFunctionAttributeEnum targetAttr, MethodInfo method)
360                 {
361                         JSFunctionAttribute [] custom_attrs = (JSFunctionAttribute [])
362                                 method.GetCustomAttributes (typeof (JSFunctionAttribute), true);
363
364                         foreach (JSFunctionAttribute attr in custom_attrs)
365                                 if ((attr.GetAttributeValue () & targetAttr) != 0)
366                                         return true;
367                         return false;
368                 }
369
370                 internal static bool IsDeletable (Identifier left, Identifier right, out bool isCtr)
371                 {
372                         Type ctr = SemanticAnalyser.map_to_ctr (left.name.Value);
373                         isCtr = ctr != null ? true : false;
374
375                         if (isCtr)
376                                 return SemanticAnalyser.get_member (left, right) == null;
377
378                         Console.WriteLine ("ctr = {0}, left = {1} ({2}); right = {3} ({4})",
379                                    ctr, left, left.GetType (), right, right.GetType ());
380                         return false;
381                 }
382
383                 /// <summary>
384                 ///   Computes the namespaces that we import from the assemblies we reference.
385                 /// </summary>
386                 public static void ComputeNamespaces ()
387                 {
388                         MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
389
390                         Hashtable cache = null;
391
392                         //
393                         // First add the assembly namespaces
394                         //
395                         if (assembly_get_namespaces != null){
396                                 int count = assemblies.Length;
397
398                                 for (int i = 0; i < count; i++){
399                                         Assembly a = assemblies [i];
400                                         string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
401                                         foreach (string ns in namespaces){
402                                                 if (ns == "")
403                                                         continue;
404                                                 Mono.CSharp.RootNamespace.Global.GetNamespace (ns, true);
405                                         }
406                                 }
407                         } else {
408                                 cache = new Hashtable ();
409                                 cache.Add ("", null);
410                                 foreach (Assembly a in assemblies) {
411                                         foreach (Type t in a.GetExportedTypes ()) {
412                                                 string ns = t.Namespace;
413                                                 if (ns == null || cache.Contains (ns))
414                                                         continue;
415                                                 Mono.CSharp.RootNamespace.Global.GetNamespace (ns, true);
416                                                 cache.Add (ns, null);
417                                         }
418                                 }
419                         }
420                 }
421         }
422 }