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;
145 ComputeNamespaces ();
146 env = new Environment (blocks);
149 foreach (ScriptBlock script_block in blocks)
150 ((ICanModifyContext) script_block).PopulateContext (env, String.Empty);
152 foreach (ScriptBlock script_block in blocks)
153 r &= script_block.Resolve (env);
158 static int anon_method_counter = -1;
159 internal static string NextAnonymousMethod {
161 anon_method_counter++;
162 return "anonymous " + anon_method_counter;
166 static int anon_regExp_counter = -1;
167 internal static string NextAnonymousRegExpObj {
169 anon_regExp_counter++;
170 return "regexp " + anon_regExp_counter;
174 internal static string CurrentAnonymousMethod {
175 get { return "anonymous " + anon_method_counter; }
178 internal static void AddLabel (string name, AST binding)
180 label_set.Enter (Symbol.CreateSymbol (name), binding);
183 internal static bool ContainsLabel (string name)
185 object r = label_set.Get (Symbol.CreateSymbol (name));
189 internal static object GetLabel (string name)
191 return label_set.Get (Symbol.CreateSymbol (name));
194 internal static void RemoveLabel (string name)
196 label_set.Remove (Symbol.CreateSymbol (name));
200 internal static void assert_type (object thisObj, Type expType)
202 if (thisObj == null || (thisObj.GetType () != expType && !thisObj.GetType ().IsSubclassOf (expType)))
203 throw new Exception ("Type error");
206 internal static bool contains (Type target_type, string name, BindingFlags flags)
208 MemberInfo [] type_props = target_type.GetMembers (flags);
209 foreach (MemberInfo mi in type_props)
215 internal static bool is_js_object (string name)
217 return contains (global_obj, name, BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
221 // We assume type is a valid native object
222 // type. Search for method name.
224 internal static bool object_contains (Type type, string name)
226 return contains (type, name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
229 internal static Type map_to_ctr (string type_name)
231 return (Type) obj_ctrs [type_name];
234 internal static MemberInfo get_member (AST left, AST right)
236 bool right_is_identifier = false;
238 if (left != null && right != null) {
239 right_is_identifier = right is Identifier;
241 Type target_type = null;
242 string prop_name = string.Empty;
243 string obj = string.Empty;
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);
253 if (target_type != null && prop_name != string.Empty)
254 return Find (target_type, prop_name);
259 internal static MemberInfo Find (Type type, string propertyName)
261 MemberInfo [] members = type.GetMember (propertyName);
262 if (members != null && members.Length > 0)
267 internal static Type map_to_prototype (object jsObj)
270 throw new Exception ("jsObj can't be null");
271 return (Type) prototypes [jsObj.GetType ()];
274 internal static void AddMethodWithEval (string name)
276 object contained = methods_with_eval [name];
277 if (contained == null)
278 methods_with_eval.Add (name, true);
281 internal static bool MethodContainsEval (string name)
283 object val = methods_with_eval [name];
287 internal static void AddMethodReferenceOutterScopeVar (string name, VariableDeclaration decl)
289 object contained = methods_with_outter_scope_refs [name];
290 if (contained == null)
291 methods_with_outter_scope_refs.Add (name, decl);
294 internal static void AddMethodVarsUsedNested (string name, VariableDeclaration decl)
296 object contained = methods_with_vars_used_nested [name];
297 if (contained == null)
298 methods_with_vars_used_nested.Add (name, decl);
301 internal static bool MethodReferenceOutterScopeVar (string name)
303 return OutterScopeVar (name) != null;
306 internal static VariableDeclaration OutterScopeVar (string name)
308 return (VariableDeclaration) methods_with_outter_scope_refs [name];
311 internal static bool MethodVarsUsedNested (string name)
313 bool r = VarUsedNested (name) != null;
317 internal static VariableDeclaration VarUsedNested (string name)
319 return (VariableDeclaration) methods_with_vars_used_nested [name];
322 internal static Type IsLiteral (AST ast)
325 Type type = ast.GetType ();
326 // FIXME: Add test for other literals (exclude StringLiteral)
327 if (type == typeof (ArrayLiteral))
333 internal static bool IsNumericConstant (object o)
335 return o is ByteConstant || o is ShortConstant ||
336 o is IntConstant || o is LongConstant ||
337 o is FloatConstant || o is DoubleConstant;
340 internal static bool NeedsToBoolean (AST ast)
342 if (ast is BooleanConstant || ast is StrictEquality)
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)
351 } else if (ast is Call || ast is Identifier)
354 Console.WriteLine ("ast.LineNumber = {0}", ast.Location.LineNumber);
355 throw new NotImplementedException ();
359 internal static bool Needs (JSFunctionAttributeEnum targetAttr, MethodInfo method)
361 JSFunctionAttribute [] custom_attrs = (JSFunctionAttribute [])
362 method.GetCustomAttributes (typeof (JSFunctionAttribute), true);
364 foreach (JSFunctionAttribute attr in custom_attrs)
365 if ((attr.GetAttributeValue () & targetAttr) != 0)
370 internal static bool IsDeletable (Identifier left, Identifier right, out bool isCtr)
372 Type ctr = SemanticAnalyser.map_to_ctr (left.name.Value);
373 isCtr = ctr != null ? true : false;
376 return SemanticAnalyser.get_member (left, right) == null;
378 Console.WriteLine ("ctr = {0}, left = {1} ({2}); right = {3} ({4})",
379 ctr, left, left.GetType (), right, right.GetType ());
384 /// Computes the namespaces that we import from the assemblies we reference.
386 public static void ComputeNamespaces ()
388 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
390 Hashtable cache = null;
393 // First add the assembly namespaces
395 if (assembly_get_namespaces != null){
396 int count = assemblies.Length;
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){
404 Mono.CSharp.RootNamespace.Global.GetNamespace (ns, true);
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))
415 Mono.CSharp.RootNamespace.Global.GetNamespace (ns, true);
416 cache.Add (ns, null);