2 // IdentificationTable.cs: Implementation of environments for jscript. Using a
3 // modified version of the algorithm and date structure presented by
4 // Andrew W. Appel in his book Modern compiler implementation in Java,
8 // Cesar Lopez Nataren (cnataren@novell.com)
10 // (C) 2003, Cesar Lopez Nataren
11 // Copyright (C) 2005 Novell Inc (http://novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Reflection;
37 using System.Collections;
39 namespace Microsoft.JScript {
41 /// Class that encapsulates a string id for faster hashing purposes.
43 internal class Symbol {
45 private static Hashtable dict = new Hashtable ();
47 internal string Value {
51 private Symbol (string name)
56 public override string ToString ()
62 /// Return the unique symbol associated with a
63 /// string. Repeated calls to CreateSymbol will return the
66 internal static Symbol CreateSymbol (string n)
68 n = LateBinding.MapToInternalName (n);
69 string u = String.Intern (n);
70 Symbol s = (Symbol) dict [u];
81 /// Associates a symbol to its declaring object.
83 internal class Binder {
88 /// If the symbol is already in the environment, resolves
89 /// collisions with external chaining.
93 internal object Value {
95 set { this.value = value; }
98 internal Binder Tail {
102 internal Symbol PrevTop {
103 get { return prev_top; }
106 internal Binder (object value, Symbol prev_top, Binder tail)
109 this.prev_top = prev_top;
115 /// Environment implementation, each key must be a Symbol and we take
118 internal class IdentificationTable {
119 private Hashtable dict = new Hashtable ();
121 private Binder marks;
122 private Stack locals;
123 private bool previous_scope = false;
124 private bool catch_scope = false;
125 internal bool CatchScope {
126 get { return catch_scope; }
131 internal IdentificationTable ()
133 locals = new Stack ();
134 locals.Push (new Hashtable ());
138 internal bool Contains (Symbol key)
140 Binder e = (Binder) dict [key];
145 /// Gets the object associated to the symbol in the table
147 internal object Get (Symbol key)
149 Binder e = (Binder) dict [key];
160 internal void Enter (Symbol key, object value)
162 Binder e = (Binder) dict [key];
165 /// If a Binder's Value is null means that it
166 /// represents a in-transit binding, we must
167 /// set its value to something useful.
169 if (e != null && e.Value == null)
173 // If 'key' is already on the table we form a
174 // Binder's chain, otherwise we include the new key
175 // represented with its association object.
177 dict [key] = new Binder (value, top, (Binder) dict [key]);
180 // make 'key' the most recent symbol bound
184 Hashtable top_ht = (Hashtable) locals.Peek ();
185 string val = key.Value;
190 /// Delete symbol from the table
192 internal void Remove (Symbol key)
194 Binder e = (Binder) dict [key];
202 internal void BeginScope ()
208 /// Remembers the current state of the table
210 internal void BeginScope (bool catchScope)
212 previous_scope = catch_scope;
213 catch_scope = catchScope;
215 marks = new Binder (null, top, marks);
218 locals.Push (new Hashtable ());
223 /// Restores the table to what it was at the most recent BeginScope
224 /// that has not already been ended
226 internal void EndScope ()
229 // Delete all the elements until we find
230 // that top is null, that occurs when we find
233 while (top != null) {
234 Binder e = (Binder) dict [top];
237 // If there's a chain we delete the first
238 // element of it, otherwise remove the symbol
250 // marks.PrevTop always contains the latest symbol
251 // which was bound before the new scope was created.
256 // delete the latest scope mark
262 catch_scope = previous_scope;
265 internal object [] CurrentLocals {
267 Stack stack = new Stack ();
270 while (_top != null) {
271 Binder e = (Binder) dict [_top];
272 stack.Push (e.Value);
275 if (stack.Count == 0)
278 object [] res = new object [stack.Count];
279 stack.CopyTo (res, 0);
284 internal bool InCurrentScope (Symbol id)
286 Hashtable hash = (Hashtable) locals.Peek ();
287 return hash.ContainsKey (id.Value) && hash [id.Value] != null;
290 internal void AddToCurrentLocals (string name, object o)
292 ((Hashtable) locals.Peek ()).Add (name, o);
295 internal DictionaryEntry [] LocalsAtDepth (int depth)
297 object [] hashes = new object [locals.Count];
298 locals.CopyTo (hashes, 0);
299 Hashtable hash = (Hashtable) hashes [locals.Count - depth - 1];
300 DictionaryEntry [] _locals = new DictionaryEntry [hash.Count];
301 hash.CopyTo (_locals, 0);
308 // Lookup table with namespace context.
310 internal class Environment {
312 private Hashtable namespaces;
314 internal Environment ()
316 namespaces = new Hashtable ();
319 // global variables identification table
321 namespaces.Add (String.Empty, new IdentificationTable ());
324 internal Environment (ScriptBlock [] blocks)
328 // FIXME: when we implement the package stm. For each package
329 // name we must add a identification table that will store
330 // id's defined inside it.
334 // integrate the builtin functions, objects, ...
340 // retrieves the identification table for the ns namespace
342 internal IdentificationTable GetIdentificationTable (string ns)
344 return (IdentificationTable) namespaces [ns];
347 internal bool Contains (string ns, Symbol key)
349 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
354 return symbols.Contains (key);
357 internal object Get (string ns, Symbol key)
359 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
364 return symbols.Get (key);
367 internal void Enter (string ns, Symbol key, object value)
369 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
372 throw new Exception (ns + " does not exist");
374 symbols.Enter (key, value);
377 internal void Remove (string ns, Symbol key)
379 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
382 throw new Exception (ns + " does not exist");
384 symbols.Remove (key);
387 internal void BeginScope (string ns)
389 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
392 throw new Exception (ns + " does not exist");
394 symbols.BeginScope ();
397 internal void BeginScope (string ns, bool catchScope)
399 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
402 throw new Exception (ns + " does not exist");
404 symbols.BeginScope (catchScope);
407 internal void EndScope (string ns)
409 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
412 throw new Exception (ns + " does not exist");
417 internal object [] CurrentLocals (string ns)
419 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
422 throw new Exception (ns + " does not exist");
424 return symbols.CurrentLocals;
427 internal int Depth (string ns)
429 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
432 throw new Exception (ns + " does not exist");
434 return symbols.depth;
437 internal bool InCurrentScope (string ns, Symbol id)
439 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
442 throw new Exception (ns + " does not exist");
444 return symbols.InCurrentScope (id);
447 internal bool CatchScope (string ns)
449 IdentificationTable symbols = (IdentificationTable) namespaces [ns];
452 throw new Exception (ns + " does not exist");
454 return symbols.CatchScope;
457 internal void BuildGlobalEnv ()
460 // built in print function
462 if (SemanticAnalyser.print)
463 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("print"), new BuiltIn ("print", false, true));
465 /* value properties of the Global Object */
466 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("NaN"), new BuiltIn ("NaN", false, false));
467 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Infinity"), new BuiltIn ("Infinity", false, false));
468 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("undefined"), new BuiltIn ("undefined", false, false));
469 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("null"), new BuiltIn ("null", false, false));
471 /* function properties of the Global Object */
472 object [] custom_attrs;
473 Type global_object = typeof (GlobalObject);
474 MethodInfo [] methods = global_object.GetMethods (BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
475 foreach (MethodInfo mi in methods) {
476 custom_attrs = mi.GetCustomAttributes (typeof (JSFunctionAttribute), false);
477 foreach (JSFunctionAttribute attr in custom_attrs)
479 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol (mi.Name), new BuiltIn (SemanticAnalyser.ImplementationName (attr.BuiltIn.ToString ()), false, true));
482 /* built in objects */
483 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Object"), new BuiltIn ("Object", true, true));
484 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Function"), new BuiltIn ("Function", true, true));
485 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Array"), new BuiltIn ("Array", true, true));
486 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("String"), new BuiltIn ("String", true, true));
487 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Boolean"), new BuiltIn ("Boolean", true, true));
488 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Number"), new BuiltIn ("Number", true, true));
489 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Math"), new BuiltIn ("Math", false, false));
490 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Date"), new BuiltIn ("Date", true, true));
491 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("RegExp"), new BuiltIn ("RegExp", true, true));
493 /* built in Error objects */
494 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("Error"), new BuiltIn ("Error", true, true));
495 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("EvalError"), new BuiltIn ("EvalError", true, true));
496 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("RangeError"), new BuiltIn ("RangeError", true, true));
497 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("ReferenceError"), new BuiltIn ("ReferenceError", true, true));
498 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("SyntaxError"), new BuiltIn ("SyntaxError", true, true));
499 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("TypeError"), new BuiltIn ("TypeError", true, true));
500 Enter (SemanticAnalyser.GlobalNamespace, Symbol.CreateSymbol ("URIError"), new BuiltIn ("URIError", true, true));