2006-01-25 Cesar Lopez Nataren <cnataren@novell.com>
[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
146                         if (assemblies != null && assemblies.Length > 0)
147                                 ComputeNamespaces ();
148
149                         env = new Environment (blocks);
150                         bool r = true;
151
152                         foreach (ScriptBlock script_block in blocks)
153                                 ((ICanModifyContext) script_block).PopulateContext (env, String.Empty);
154
155                         foreach (ScriptBlock script_block in blocks)
156                                 r &= script_block.Resolve (env);
157
158                         return r;
159                 }
160
161                 static int anon_method_counter = -1;
162                 internal static string NextAnonymousMethod {
163                         get { 
164                                 anon_method_counter++;
165                                 return "anonymous " + anon_method_counter; 
166                         }
167                 }
168
169                 static int anon_regExp_counter = -1;
170                 internal static string NextAnonymousRegExpObj {
171                         get {
172                                 anon_regExp_counter++;
173                                 return "regexp " + anon_regExp_counter;
174                         }
175                 }
176                 
177                 internal static string CurrentAnonymousMethod {
178                         get { return "anonymous " + anon_method_counter; }
179                 }
180
181                 internal static void AddLabel (string name, AST binding)
182                 {
183                         label_set.Enter (Symbol.CreateSymbol (name), binding);
184                 }
185                 
186                 internal static bool ContainsLabel (string name)
187                 {
188                         object r = label_set.Get (Symbol.CreateSymbol (name));
189                         return r != null;
190                 }
191
192                 internal static object GetLabel (string name) 
193                 {
194                         return label_set.Get (Symbol.CreateSymbol (name));
195                 }
196
197                 internal static void RemoveLabel (string name)
198                 {
199                         label_set.Remove (Symbol.CreateSymbol (name));
200                 }
201
202
203                 internal static void assert_type (object thisObj, Type expType)
204                 {
205                         if (thisObj == null || (thisObj.GetType () != expType && !thisObj.GetType ().IsSubclassOf (expType)))
206                                 throw new Exception ("Type error");
207                 }
208
209                 internal static bool contains (Type target_type, string name, BindingFlags flags)
210                 {
211                         MemberInfo [] type_props = target_type.GetMembers (flags);
212                         foreach (MemberInfo mi in type_props)
213                                 if (mi.Name == name)
214                                         return true;
215                         return false;
216                 }
217
218                 internal static bool is_js_object (string name)
219                 {                       
220                         return contains (global_obj, name, BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
221                 }
222                 
223                 //
224                 // We assume type is a valid native object
225                 // type. Search for method name.
226                 //
227                 internal static bool object_contains (Type type, string name)
228                 {
229                         return contains (type, name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
230                 }
231
232                 internal static Type map_to_ctr (string type_name)
233                 {
234                         return (Type) obj_ctrs [type_name];
235                 }
236
237                 internal static MemberInfo get_member (AST left, AST right)
238                 {
239                         bool right_is_identifier = false;
240                         
241                         if (left != null && right != null) {
242                                 right_is_identifier = right is Identifier;
243
244                                 Type target_type = null;
245                                 string prop_name = string.Empty;
246                                 string obj = string.Empty;
247                                         
248                                 if (left is Identifier && right_is_identifier) {
249                                         obj =  ((Identifier) left).name.Value;
250                                         prop_name = ((Identifier) right).name.Value;
251                                         target_type = SemanticAnalyser.map_to_ctr (obj);
252                                 } else if (left is ICanLookupPrototype && right_is_identifier) {
253                                         prop_name = ((Identifier) right).name.Value;
254                                         target_type = SemanticAnalyser.map_to_prototype (left);
255                                 }
256                                 if (target_type != null && prop_name != string.Empty)
257                                         return Find (target_type, prop_name);
258                         }
259                         return null;
260                 }
261
262                 internal static MemberInfo Find (Type type, string propertyName)
263                 {
264                         MemberInfo [] members = type.GetMember (propertyName);
265                         if (members != null && members.Length > 0)
266                                 return members [0];
267                         return null;
268                 }
269
270                 internal static Type map_to_prototype (object jsObj)
271                 {
272                         if (jsObj == null)
273                                 throw new Exception ("jsObj can't be null");
274                         return (Type) prototypes [jsObj.GetType ()];
275                 }
276
277                 internal static void AddMethodWithEval (string name)
278                 {
279                         object contained = methods_with_eval [name];
280                         if (contained == null)
281                                 methods_with_eval.Add (name, true);
282                 }
283
284                 internal static bool MethodContainsEval (string name)
285                 {
286                         object val = methods_with_eval [name];
287                         return val != null;
288                 }
289
290                 internal static void AddMethodReferenceOutterScopeVar (string name, VariableDeclaration decl)
291                 {
292                         object contained = methods_with_outter_scope_refs [name];
293                         if (contained == null)
294                                 methods_with_outter_scope_refs.Add (name, decl);
295                 }
296
297                 internal static void AddMethodVarsUsedNested (string name, VariableDeclaration decl)
298                 {
299                         object contained = methods_with_vars_used_nested [name];
300                         if (contained == null)
301                                 methods_with_vars_used_nested.Add (name, decl);
302                 }
303
304                 internal static bool MethodReferenceOutterScopeVar (string name)
305                 {
306                         return OutterScopeVar (name) != null;
307                 }
308
309                 internal static VariableDeclaration OutterScopeVar (string name)
310                 {
311                         return (VariableDeclaration) methods_with_outter_scope_refs [name];
312                 }
313
314                 internal static bool MethodVarsUsedNested (string name)
315                 {
316                         bool r = VarUsedNested (name) != null;
317                         return r;
318                 }
319
320                 internal static VariableDeclaration VarUsedNested (string name)
321                 {
322                         return (VariableDeclaration) methods_with_vars_used_nested [name];
323                 }
324
325                 internal static Type IsLiteral (AST ast)
326                 {
327                         if (ast != null) {
328                                 Type type = ast.GetType ();
329                                 // FIXME: Add test for other literals (exclude StringLiteral)
330                                 if (type == typeof (ArrayLiteral))
331                                         return type;
332                         }
333                         return null;
334                 }
335
336                 internal static bool IsNumericConstant (object o)
337                 {
338                         return o is ByteConstant || o is ShortConstant ||
339                                 o is IntConstant || o is LongConstant ||
340                                 o is FloatConstant || o is DoubleConstant;
341                 }
342
343                 internal static bool NeedsToBoolean (AST ast)
344                 {
345                         if (ast is BooleanConstant || ast is StrictEquality)
346                                 return false;
347                         else if (ast is Expression)
348                                 return NeedsToBoolean (((Expression) ast).Last);
349                         else if (ast is Unary) {
350                                 Unary unary = (Unary) ast;
351                                 if (unary.oper != JSToken.LogicalNot)
352                                         return true;
353                                 return false;
354                         } else if (ast is Call || ast is Identifier)
355                                 return true;
356                         else {
357                                 Console.WriteLine ("ast.LineNumber = {0}", ast.Location.LineNumber);
358                                 throw new NotImplementedException ();
359                         }
360                 }
361
362                 internal static bool Needs (JSFunctionAttributeEnum targetAttr, MethodInfo method)
363                 {
364                         JSFunctionAttribute [] custom_attrs = (JSFunctionAttribute [])
365                                 method.GetCustomAttributes (typeof (JSFunctionAttribute), true);
366
367                         foreach (JSFunctionAttribute attr in custom_attrs)
368                                 if ((attr.GetAttributeValue () & targetAttr) != 0)
369                                         return true;
370                         return false;
371                 }
372
373                 internal static bool IsDeletable (Identifier left, Identifier right, out bool isCtr)
374                 {
375                         Type ctr = SemanticAnalyser.map_to_ctr (left.name.Value);
376                         isCtr = ctr != null ? true : false;
377
378                         if (isCtr)
379                                 return SemanticAnalyser.get_member (left, right) == null;
380
381                         Console.WriteLine ("ctr = {0}, left = {1} ({2}); right = {3} ({4})",
382                                    ctr, left, left.GetType (), right, right.GetType ());
383                         return false;
384                 }
385
386                 /// <summary>
387                 ///   Computes the namespaces that we import from the assemblies we reference.
388                 /// </summary>
389                 public static void ComputeNamespaces ()
390                 {
391                         MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
392
393                         Hashtable cache = null;
394
395                         //
396                         // First add the assembly namespaces
397                         //
398                         if (assembly_get_namespaces != null){
399                                 int count = assemblies.Length;
400
401                                 for (int i = 0; i < count; i++){
402                                         Assembly a = assemblies [i];
403                                         string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
404                                         foreach (string ns in namespaces){
405                                                 if (ns == "")
406                                                         continue;
407                                                 Namespace.GetNamespace (ns, true);
408                                         }
409                                 }
410                         } else {
411                                 cache = new Hashtable ();
412                                 cache.Add ("", null);
413                                 foreach (Assembly a in assemblies) {
414                                         foreach (Type t in a.GetExportedTypes ()) {
415                                                 string ns = t.Namespace;
416                                                 if (ns == null || cache.Contains (ns))
417                                                         continue;
418                                                 Namespace.GetNamespace (ns, true);
419                                                 cache.Add (ns, null);
420                                         }
421                                 }
422                         }
423                 }
424         }
425 }