2 // SemanticAnalyser.cs: Initiate the type check and identification phases.
7 // (C) 2003, 2004 Cesar Lopez Nataren, <cesar@ciencias.unam.mx>
8 // (C) 2005, Novell Inc.
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
33 using System.Reflection;
34 using System.Collections;
36 namespace Microsoft.JScript {
38 internal class SemanticAnalyser {
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;
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 ();
53 // Type to GlobalObject
55 private static Type global_obj = typeof (GlobalObject);
57 internal static bool NoFast = true;
58 private static Assembly [] assemblies;
60 private static readonly string global_namespace = String.Empty;
61 internal static string GlobalNamespace {
62 get { return global_namespace; }
65 static SemanticAnalyser ()
67 label_set = new IdentificationTable ();
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));
80 prototypes = new Hashtable ();
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));
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));
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));
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));
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);
136 internal static string ImplementationName (string name)
138 int i = name.LastIndexOf ('_');
139 return name.Substring (i + 1);
142 internal static bool Run (ScriptBlock [] blocks, Assembly [] ref_items)
144 assemblies = ref_items;
146 if (assemblies != null && assemblies.Length > 0)
147 ComputeNamespaces ();
149 env = new Environment (blocks);
152 foreach (ScriptBlock script_block in blocks)
153 ((ICanModifyContext) script_block).PopulateContext (env, String.Empty);
155 foreach (ScriptBlock script_block in blocks)
156 r &= script_block.Resolve (env);
161 static int anon_method_counter = -1;
162 internal static string NextAnonymousMethod {
164 anon_method_counter++;
165 return "anonymous " + anon_method_counter;
169 static int anon_regExp_counter = -1;
170 internal static string NextAnonymousRegExpObj {
172 anon_regExp_counter++;
173 return "regexp " + anon_regExp_counter;
177 internal static string CurrentAnonymousMethod {
178 get { return "anonymous " + anon_method_counter; }
181 internal static void AddLabel (string name, AST binding)
183 label_set.Enter (Symbol.CreateSymbol (name), binding);
186 internal static bool ContainsLabel (string name)
188 object r = label_set.Get (Symbol.CreateSymbol (name));
192 internal static object GetLabel (string name)
194 return label_set.Get (Symbol.CreateSymbol (name));
197 internal static void RemoveLabel (string name)
199 label_set.Remove (Symbol.CreateSymbol (name));
203 internal static void assert_type (object thisObj, Type expType)
205 if (thisObj == null || (thisObj.GetType () != expType && !thisObj.GetType ().IsSubclassOf (expType)))
206 throw new Exception ("Type error");
209 internal static bool contains (Type target_type, string name, BindingFlags flags)
211 MemberInfo [] type_props = target_type.GetMembers (flags);
212 foreach (MemberInfo mi in type_props)
218 internal static bool is_js_object (string name)
220 return contains (global_obj, name, BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
224 // We assume type is a valid native object
225 // type. Search for method name.
227 internal static bool object_contains (Type type, string name)
229 return contains (type, name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
232 internal static Type map_to_ctr (string type_name)
234 return (Type) obj_ctrs [type_name];
237 internal static MemberInfo get_member (AST left, AST right)
239 bool right_is_identifier = false;
241 if (left != null && right != null) {
242 right_is_identifier = right is Identifier;
244 Type target_type = null;
245 string prop_name = string.Empty;
246 string obj = string.Empty;
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);
256 if (target_type != null && prop_name != string.Empty)
257 return Find (target_type, prop_name);
262 internal static MemberInfo Find (Type type, string propertyName)
264 MemberInfo [] members = type.GetMember (propertyName);
265 if (members != null && members.Length > 0)
270 internal static Type map_to_prototype (object jsObj)
273 throw new Exception ("jsObj can't be null");
274 return (Type) prototypes [jsObj.GetType ()];
277 internal static void AddMethodWithEval (string name)
279 object contained = methods_with_eval [name];
280 if (contained == null)
281 methods_with_eval.Add (name, true);
284 internal static bool MethodContainsEval (string name)
286 object val = methods_with_eval [name];
290 internal static void AddMethodReferenceOutterScopeVar (string name, VariableDeclaration decl)
292 object contained = methods_with_outter_scope_refs [name];
293 if (contained == null)
294 methods_with_outter_scope_refs.Add (name, decl);
297 internal static void AddMethodVarsUsedNested (string name, VariableDeclaration decl)
299 object contained = methods_with_vars_used_nested [name];
300 if (contained == null)
301 methods_with_vars_used_nested.Add (name, decl);
304 internal static bool MethodReferenceOutterScopeVar (string name)
306 return OutterScopeVar (name) != null;
309 internal static VariableDeclaration OutterScopeVar (string name)
311 return (VariableDeclaration) methods_with_outter_scope_refs [name];
314 internal static bool MethodVarsUsedNested (string name)
316 bool r = VarUsedNested (name) != null;
320 internal static VariableDeclaration VarUsedNested (string name)
322 return (VariableDeclaration) methods_with_vars_used_nested [name];
325 internal static Type IsLiteral (AST ast)
328 Type type = ast.GetType ();
329 // FIXME: Add test for other literals (exclude StringLiteral)
330 if (type == typeof (ArrayLiteral))
336 internal static bool IsNumericConstant (object o)
338 return o is ByteConstant || o is ShortConstant ||
339 o is IntConstant || o is LongConstant ||
340 o is FloatConstant || o is DoubleConstant;
343 internal static bool NeedsToBoolean (AST ast)
345 if (ast is BooleanConstant || ast is StrictEquality)
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)
354 } else if (ast is Call || ast is Identifier)
357 Console.WriteLine ("ast.LineNumber = {0}", ast.Location.LineNumber);
358 throw new NotImplementedException ();
362 internal static bool Needs (JSFunctionAttributeEnum targetAttr, MethodInfo method)
364 JSFunctionAttribute [] custom_attrs = (JSFunctionAttribute [])
365 method.GetCustomAttributes (typeof (JSFunctionAttribute), true);
367 foreach (JSFunctionAttribute attr in custom_attrs)
368 if ((attr.GetAttributeValue () & targetAttr) != 0)
373 internal static bool IsDeletable (Identifier left, Identifier right, out bool isCtr)
375 Type ctr = SemanticAnalyser.map_to_ctr (left.name.Value);
376 isCtr = ctr != null ? true : false;
379 return SemanticAnalyser.get_member (left, right) == null;
381 Console.WriteLine ("ctr = {0}, left = {1} ({2}); right = {3} ({4})",
382 ctr, left, left.GetType (), right, right.GetType ());
387 /// Computes the namespaces that we import from the assemblies we reference.
389 public static void ComputeNamespaces ()
391 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
393 Hashtable cache = null;
396 // First add the assembly namespaces
398 if (assembly_get_namespaces != null){
399 int count = assemblies.Length;
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){
407 Namespace.GetNamespace (ns, true);
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))
418 Namespace.GetNamespace (ns, true);
419 cache.Add (ns, null);