public SymEntry EnsureSymbolType(SymEntry sym, System.Type tExpected, FileRange location) { if (sym == null) return null; /* Type tSym = sym.GetType(); if (tSym == tExpected) return sym; if (tSym.IsSubclassOf(tExpected)) return sym; */ bool fMatch = SymbolEngine.TypeEntry.IsAssignable(sym.GetType(), tExpected); if (fMatch) return sym; ThrowError(SymbolError.BadSymbolType(sym, tExpected, location)); /* this.ThrowError(Code.cBadSymbolType, location, "Symbol '" + sym.Name + "' must be of type '" + tExpected.ToString() + "', not '" + sym.GetType().ToString() + "'"); */ return sym; }
// Dump the scope to an xml file public void Dump(XmlWriter o, bool fRecursive) { o.WriteStartElement("scope"); o.WriteAttributeString("name", m_szDebugName); ILookupController p = this.m_pController; o.WriteAttributeString("controller", (p == null) ? "none" : ((object)p).GetType().Name); /* * if (m_SuperScope != null) * { * o.WriteAttributeString("super", m_SuperScope.m_szDebugName); * } */ System.Collections.IDictionaryEnumerator e = m_table.GetEnumerator(); while (e.MoveNext()) { string str = (string)e.Key; SymEntry sym = (SymEntry)e.Value; sym.Dump(o, fRecursive); } o.WriteEndElement(); // scope }
// We only need Lookup() during the resolve phase (because that's the only time // we need to convert text into symbols) // After that, we can just use the symbols directly // Lookup an entry in a specific scope // If it doesn't exist, then return null if !fMustExist and throw if fMustExist public SymEntry LookupSymbol(Scope scope, Identifier id, bool fMustExist) { SymEntry s = scope.LookupSymbol(id.Text); if (fMustExist && s == null) { ThrowError(SymbolError.UndefinedSymbol(id)); } return s; }
// Verify integrity of all symbol elements in this scope public void DebugCheck(ISemanticResolver s) { System.Collections.IDictionaryEnumerator e = m_table.GetEnumerator(); while (e.MoveNext()) { string str = (string)e.Key; SymEntry sym = (SymEntry)e.Value; sym.DebugCheck(s); } }
// Lookup a system type // Context-free public TypeEntry LookupSystemType(string st) { NamespaceEntry nsSystem = (NamespaceEntry) LookupSymbol(m_scopeGlobal, "System", true); Scope scopeSystem = nsSystem.ChildScope; SymEntry s = LookupSymbol(scopeSystem, st, true); // An end-user program can't lookup system types, so this assert should be fine. Debug.Assert(s is TypeEntry, "Expected '" + st + "' is a type"); return s as TypeEntry; }
// Dump all the raw entries public void DumpKeys() { Console.WriteLine("*** Debug dump of keys in scope #{0},{1} [", this.m_id, this.m_szDebugName); System.Collections.IDictionaryEnumerator e = m_table.GetEnumerator(); while (e.MoveNext()) { string str = (string)e.Key; SymEntry sym = (SymEntry)e.Value; Console.WriteLine("{0} is a {1}", str, sym.ToString()); } Console.WriteLine("] End dump"); }
// Lookup a symbol in the current context. // The context includes the lexical scope stack, super scopes, // and using directives // If it doesn't exist, then return null if !fMustExist and throw exception if fMustExist public virtual SymEntry LookupSymbolWithContext(Identifier id, bool fMustExist) { string strName = id.Text; // Search through stack of lexical scopes SymEntry sym = null; Scope t = m_CurrentContext; while(t != null) { sym = LookupSymbol(t, id, false); // <-- smart lookup, go through ILookupController if (sym != null) return sym; t = t.m_LexicalParent; } // Don't need this any more with ILookupControllers #if false // Check using directives if not found in the current scope stack // Do this by traversing the scope stack and looking for UserNamespaceEntry // (we can never be in an imported namespace, so that's ok) t = m_CurrentContext; while (t != null) { AST.NamespaceDecl node = t.Node as AST.NamespaceDecl; if (node != null) { sym = node.LookupSymbolInUsingDirectives(this, id); if (sym != null) return sym; } t = t.m_LexicalParent; } #endif // Symbol not found if (fMustExist) { //ThrowError_UndefinedSymbol(id); ThrowError(SymbolError.UndefinedSymbol(id)); } return null; }
// Get rid of this function public SymEntry LookupSymbol(Scope scope, string st, bool fMustExist) { SymEntry s = scope.LookupSymbol(st); bool f= false; if (f) { System.Xml.XmlWriter o = new System.Xml.XmlTextWriter(new System.IO.StreamWriter("dump.xml")); scope.Dump(o, true); o.Close(); } if (fMustExist && s == null) { FileRange range = new FileRange(); range.Filename = "<not specified>"; Identifier id = new Identifier(st, range); //ThrowError_UndefinedSymbol(id); ThrowError(SymbolError.UndefinedSymbol(id)); } return s; }
/// <summary> /// Add a symbol to this scope. (SymEntry contains the string name) /// <seealso cref="AddAliasSymbol"/> /// </summary> /// <remarks> /// Adds the given Symbol to this scope, and indexes it by the symbol's name. /// </remarks> /// <param name="s">The symbol to add</param> public void AddSymbol(SymEntry s) { Debug.Assert(!m_fIsLocked, "Can't add to a locked scope"); Debug.Assert(s != null); Debug.Assert(s.Name != null); // If we try to add the symbol and it's already there, we have a Symbol-Redefinition // error. Hashtable.Add() will throw an exception, we catch that, and then throw our // own version. // We choose to catch, rather than to check first, because we optimize for the // non-error case. try { m_table.Add(s.Name, s); // this already throws } catch (ArgumentException) { // @todo - How should we handle this error? Debug.Assert(false, "@todo - symbol already defined"); } }
/// <summary> /// Add a symbol under an aliased name. /// </summary> /// <remarks> /// Add an existing symbol entry, but indexed under a new name /// <para><example> /// [globalscope].AddAliasSymbol("int", [SymEntry for System.Int32]); /// </example></para> /// <seealso cref="AddSymbol"/> /// </remarks> /// <param name="stAliasName">Aliased name of the symbol</param> /// <param name="s">Symbol to add</param> public void AddAliasSymbol(string stAliasName, SymEntry s) { Debug.Assert(!m_fIsLocked, "Can't add to a locked scope"); m_table.Add(stAliasName, s); }
/// <summary> /// Add a symbol to this scope. (SymEntry contains the string name) /// <seealso cref="AddAliasSymbol"/> /// </summary> /// <remarks> /// Adds the given Symbol to this scope, and indexes it by the symbol's name. /// </remarks> /// <param name="s">The symbol to add</param> public void AddSymbol(SymEntry s) { Debug.Assert(!m_fIsLocked, "Can't add to a locked scope"); Debug.Assert(s != null); Debug.Assert(s.Name != null); // If we try to add the symbol and it's already there, we have a Symbol-Redefinition // error. Hashtable.Add() will throw an exception, we catch that, and then throw our // own version. // We choose to catch, rather than to check first, because we optimize for the // non-error case. try { m_table.Add(s.Name, s); // this already throws } catch(ArgumentException) { // @todo - How should we handle this error? Debug.Assert(false, "@todo - symbol already defined"); } }
//----------------------------------------------------------------------------- // The symbol is of the wrong type. //----------------------------------------------------------------------------- public static SymbolErrorException BadSymbolType(SymEntry sym, System.Type tExpected, FileRange location) { return new SymbolErrorException( Code.cBadSymbolType, location, "Symbol '" + sym.Name + "' must be of type '" + tExpected.ToString() + "', not '" + sym.GetType().ToString() + "'" ); }
//----------------------------------------------------------------------------- // Create the scopes for an imported types //----------------------------------------------------------------------------- Scope CreateImportedContext(System.Type tImport) { // Traverse namespaces to find scope Scope scope = m_scopeGlobal; string s = tImport.ToString(); // In a type's string name, the '.' separates namespaces, // the '+' separates for nested classes. // Valid form: // i.i.i+i+i+i int iStart = 0; int i = s.IndexOf('.'); // Search past namespaces while(i != -1) { string stNamespace = s.Substring(iStart, i - iStart); SymEntry sym = LookupSymbol(scope, stNamespace, false); if (sym == null) { ImportedNamespaceEntry nsImported = new ImportedNamespaceEntry( stNamespace, s.Substring(0, i) ); scope.AddSymbol(nsImported); scope = nsImported.ChildScope; } else { // If the symbol already exists, must be a namespace if (sym is NamespaceEntry) { scope = ((NamespaceEntry) sym).ChildScope; } else { ThrowError(SymbolError.IllegalAssembly(tImport.Assembly, "Illegal type: " + s)); } } iStart = i + 1; i = s.IndexOf('.', iStart); } // If we're not a nested type, then we can return the scope now if (tImport.DeclaringType == null) { Debug.Assert(s.Substring(iStart) == tImport.Name); return scope; } // Containing class should have already been added. Debug.Assert(TryLookupCLRType(tImport.DeclaringType) != null); // Else we have to traverse the class scopes to find out containing scope. // n.n. c1+c2 i = s.IndexOf('+', iStart); while (i != -1) { string stClass = s.Substring(iStart, i - iStart); TypeEntry tBlue = (TypeEntry) LookupSymbol(scope, stClass, true); scope = tBlue.MemberScope; Debug.Assert(scope != null); iStart = i + 1; i = s.IndexOf('+', iStart); } Debug.Assert(s.Substring(iStart) == tImport.Name); return scope; }