Changeset 8

Show
Ignore:
Timestamp:
07/01/08 17:47:50 (6 months ago)
Author:
lb
Message:

Pragma SymbolTAble

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/xtc/lang/PragmaSymbolTable.java

    r5 r8  
    11package xtc.lang; 
    22 
     3import java.util.ArrayList; 
     4import java.util.HashMap; 
     5import java.util.Iterator; 
     6import java.util.List; 
     7import java.util.Map; 
     8 
     9import xtc.tree.Node; 
     10import xtc.tree.Printer; 
     11import xtc.util.EmptyIterator; 
    312import xtc.util.SymbolTable; 
     13import xtc.util.Utilities; 
     14import xtc.util.SymbolTable.Scope; 
     15 
    416 
    517public class PragmaSymbolTable extends SymbolTable { 
     18        public class PragmaScope { 
     19                 /** The name. */ 
     20            String name; 
     21 
     22            /** The fully qualified name. */ 
     23            String qName; 
     24 
     25            /** The parent scope. */ 
     26            PragmaScope parent; 
     27 
     28            /** The nested scopes, if any. */ 
     29            Map<String, PragmaScope> pscopes; 
     30 
     31            /** The map from symbols to values, if any. */ 
     32            Map<String, Object> symbols; 
     33 
     34                public PragmaScope(String pragmaScope) {  
     35                        this.name = name; 
     36                        this.qName = name; 
     37                } 
     38                  /** 
     39             * Create a new nested PragmaScope with the specified unqualified name 
     40             * and parent. 
     41             * 
     42             * @param name The unqualified name. 
     43             * @param parent The parent. 
     44             * @throws IllegalArgumentException 
     45             *   Signals that the specified parent already has a nested scope 
     46             *   with the specified name. 
     47             */ 
     48            PragmaScope(String name, PragmaScope parent) { 
     49              if ((null != parent.pscopes) && parent.pscopes.containsKey(name)) { 
     50                throw new IllegalArgumentException("Scope " + parent.qName + 
     51                                                   " already contains scope " + name); 
     52              } 
     53              this.name   = name; 
     54              this.qName  = Utilities.qualify(parent.qName, name); 
     55              this.parent = parent; 
     56              if (null == parent.pscopes) { 
     57                parent.pscopes = new HashMap<String, PragmaScope>(); 
     58              } 
     59              parent.pscopes.put(name, this); 
     60            } 
     61 
     62            /** 
     63             * Get this scope's unqualfied name. 
     64             * 
     65             * @return This scope's unqualified name. 
     66             */ 
     67            public String getName() { 
     68              return name; 
     69            } 
     70 
     71            /** 
     72             * Get this scope's qualified name. 
     73             * 
     74             * @return This scope's qualified name. 
     75             */ 
     76            public String getQualifiedName() { 
     77              return qName; 
     78            } 
     79 
     80            /** 
     81             * Update this scope's qualified name relative to the parent 
     82             * scope's qualified name.  This method also requalifies any 
     83             * nested scopes' qualified names.  It must not be called on the 
     84             * root scope. 
     85             */ 
     86            void requalify() { 
     87              qName = Utilities.qualify(parent.qName, name); 
     88 
     89              if (null != pscopes) { 
     90                for (PragmaScope scope : pscopes.values()) { 
     91                  scope.requalify(); 
     92                } 
     93              } 
     94            } 
     95 
     96            /** 
     97             * Determine whether this scope is the root scope. 
     98             * 
     99             * @return <code>true</code> if this scope is the root scope. 
     100             */ 
     101            public boolean isRoot() { 
     102              return (null == parent); 
     103            } 
     104 
     105            /** 
     106             * Get this scope's parent. 
     107             * 
     108             * @return This scope's parent scope or <code>null</code> if this 
     109             *   scope does not have a parent (i.e., is the root scope). 
     110             */ 
     111            public PragmaScope getParent() { 
     112              return parent; 
     113            } 
     114 
     115            /** 
     116             * Determine whether this scope has any nested scopes. 
     117             * 
     118             * @return <code>true</code> if this scope has any nested scopes. 
     119             */ 
     120            public boolean hasNested() { 
     121              return ((null != pscopes) && (0 < pscopes.size())); 
     122            } 
     123 
     124            /** 
     125             * Get an iterator over the names of all nested scopes. 
     126             * 
     127             * @return An iterator over the nested scopes. 
     128             */ 
     129            public Iterator<String> nested() { 
     130              if (null == pscopes) { 
     131                return EmptyIterator.value(); 
     132              } else { 
     133                return pscopes.keySet().iterator(); 
     134              } 
     135            } 
     136 
     137            /** 
     138             * Determine whether this scope has the specified unqualified 
     139             * nested scope. 
     140             * 
     141             * @param name The nested scope's unqualified name. 
     142             * @return <code>true</code> if the corresponding scope exists. 
     143             */ 
     144            public boolean hasNested(String name) { 
     145              return (null != getNested(name)); 
     146            } 
     147 
     148            /** 
     149             * Get the nested scope with the specified unqualified name. 
     150             * 
     151             * @param name The nested scope's unqualified name. 
     152             * @return The corresponding scope or <code>null</code> if there is 
     153             *   no such scope. 
     154             */ 
     155            public PragmaScope getNested(String name) { 
     156              return (null == pscopes)? null : pscopes.get(name); 
     157            } 
     158 
     159            /** 
     160             * Determine whether the scope with the specified unqualified name 
     161             * can be merged into this scope.  A nested scope can be merged if 
     162             * it (1) does not contain any bindings with the same names as 
     163             * this scope's bindings and (2) does not have any children with 
     164             * the same names as this scope's children. 
     165             * 
     166             * @param name The nested scope's unqualified name. 
     167             * @return <code>true</code> if the scope can be merged. 
     168             * @throws IllegalArgumentException Signals that this scope does 
     169             *   not have a nested scope with the specified name. 
     170             */ 
     171            public boolean isMergeable(String name) { 
     172              PragmaScope nested = getNested(name); 
     173 
     174              if (null == nested) { 
     175                throw new IllegalArgumentException("Scope " + qName + " does not " + 
     176                                                   " contain scope " + name); 
     177              } 
     178 
     179              if (null != nested.pscopes) { 
     180                // Note that this scope must have nested scopes, since we just 
     181                // looked one up. 
     182                for (String s : nested.pscopes.keySet()) { 
     183                  if ((! s.equals(name)) && this.pscopes.containsKey(s)) { 
     184                    return false; 
     185                  } 
     186                } 
     187              } 
     188 
     189              if ((null != this.symbols) && (null != nested.symbols)) { 
     190                for (String s : nested.symbols.keySet()) { 
     191                  if (this.symbols.containsKey(s)) { 
     192                    return false; 
     193                  } 
     194                } 
     195              } 
     196 
     197              return true; 
     198            } 
     199 
     200            /** 
     201             * Merge the nested scope with the specified unqualified name into 
     202             * this scope. 
     203             * 
     204             * @param name The nested scope's unqualified name. 
     205             * @throws IllegalArgumentException Signals that (1) this scope 
     206             *   does not have a nested scope with the specified name, (2) any 
     207             *   of the nested scope's children has the same name as one of 
     208             *   this scope's children, or (3) any of the nested scope's 
     209             *   bindings has the same name as one of this scope's bindings. 
     210             */ 
     211            public void merge(String name) { 
     212              final PragmaScope nested = getNested(name); 
     213 
     214              // Make sure the nested scope is mergeable.  Note that the 
     215              // nested scope must exist in the consequence of the 
     216              // if-statement, since isMergeable signals an exception for 
     217              // non-existent scopes. 
     218              if (! isMergeable(name)) { 
     219                throw new IllegalArgumentException("Scope " + nested.qName + 
     220                                                   " cannot be merged into the parent"); 
     221              } 
     222 
     223              // Remove the nested scope. 
     224              this.pscopes.remove(name); 
     225 
     226              // Add the nested scope's children. 
     227              if (null != nested.pscopes) { 
     228                this.pscopes.putAll(nested.pscopes); 
     229 
     230                for (PragmaScope s : nested.pscopes.values()) { 
     231                  s.parent = this; 
     232                  s.requalify(); 
     233                } 
     234              } 
     235 
     236              // Add the nested scope's bindings. 
     237              if (null != nested.symbols) { 
     238                if (null == this.symbols) { 
     239                  this.symbols = nested.symbols; 
     240                } else { 
     241                  this.symbols.putAll(nested.symbols); 
     242                } 
     243              } 
     244 
     245              // Invalidate the nested scope. 
     246              nested.parent  = null; 
     247              nested.name    = null; 
     248              nested.qName   = null; 
     249              nested.pscopes  = null; 
     250              nested.symbols = null; 
     251            } 
     252 
     253            /** 
     254             * Determine whether this scope has any local definitions. 
     255             * 
     256             * @return <code>true</code> if this scope has any local 
     257             *   definitions. 
     258             */ 
     259            public boolean hasSymbols() { 
     260              return ((null != symbols) && (0 < symbols.size())); 
     261            } 
     262 
     263            /** 
     264             * Get an iterator over the all locally defined symbols. 
     265             * 
     266             * @return An iterator over the locally defined symbols. 
     267             */ 
     268            public Iterator<String> symbols() { 
     269              if (null == symbols) { 
     270                return EmptyIterator.value(); 
     271              } else { 
     272                return symbols.keySet().iterator(); 
     273              } 
     274            } 
     275 
     276            /** 
     277             * Determine whether the specified symbol is defined in this 
     278             * scope. 
     279             * 
     280             * @param symbol The unqualified symbol. 
     281             * @return <code>true</code> if the symbol is defined in this 
     282             *   scope. 
     283             */ 
     284            public boolean isDefinedLocally(String symbol) { 
     285              return (null == symbols)? false : symbols.containsKey(symbol); 
     286            } 
     287 
     288            /** 
     289             * Determine whether the specified unqualified symbol is defined 
     290             * in this scope or any of its ancestors. 
     291             * 
     292             * @param symbol The unqualified symbol. 
     293             * @return <code>true</code> if the symbol is defined in this scope 
     294             *   or any of its ancestors. 
     295             */ 
     296            public boolean isDefined(String symbol) { 
     297              return (null != lookupScope(symbol)); 
     298            } 
     299 
     300            /** 
     301             * Determine whether the specified symbol is defined multiple 
     302             * times in this scope or any of its ancestors. 
     303             * 
     304             * @param symbol The unqualified symbol. 
     305             * @return <code>true</code> if the symbol is defined multiple 
     306             *   times. 
     307             */ 
     308            public boolean isDefinedMultiply(String symbol) { 
     309              PragmaScope scope = lookupScope(symbol); 
     310              return (null == scope)? false : scope.symbols.get(symbol) instanceof List; 
     311            } 
     312 
     313            /** 
     314             * Get the scope defining the specified unqualified symbol.  This 
     315             * method searches this scope and all its ancestors, returning the 
     316             * first defining scope. 
     317             * 
     318             * @param symbol The unqualified symbol. 
     319             * @return The definining scope or <code>null</code> if there is 
     320             *   no such scope. 
     321             */ 
     322            public PragmaScope lookupScope(String symbol) { 
     323              PragmaScope scope = this; 
     324              do { 
     325                if ((null != scope.symbols) && (scope.symbols.containsKey(symbol))) { 
     326                  return scope; 
     327                } 
     328                scope = scope.parent; 
     329              } while (null != scope); 
     330              return null; 
     331            } 
     332 
     333            /** 
     334             * Get the value for the specified unqualified symbol.  This 
     335             * method searches this scope and all its ancestors, returning the 
     336             * value of the first definition. 
     337             * 
     338             * @param symbol The unqualified symbol. 
     339             * @return The corresponding value or <code>null</code> if there is 
     340             *   no definition. 
     341             */ 
     342            public Object lookup(String symbol) { 
     343              PragmaScope scope = lookupScope(symbol); 
     344              return (null == scope)? null : scope.symbols.get(symbol); 
     345            } 
     346 
     347            /** 
     348             * Get the scope named by the specified unqualified symbol, which 
     349             * is nested in the scope defining the symbol.  This method 
     350             * searches this scope and all its ancestors, up to the first 
     351             * defining scope.  It then looks for the nested scope with the 
     352             * same name. 
     353             * 
     354             * @param symbol The unqualified symbol. 
     355             * @return The bound scope or <code>null</code> if there is no 
     356             *   definition or nested scope with the same name. 
     357             */ 
     358            public PragmaScope lookupBoundScope(String symbol) { 
     359              PragmaScope scope = lookupScope(symbol); 
     360              return (null == scope)? null : scope.getNested(symbol); 
     361            } 
     362 
     363            /** 
     364             * Get the local value for the specified unqualified symbol. 
     365             * 
     366             * @param symbol The unqualified symbol. 
     367             * @return The corresponding value or <code>null</code> if there is 
     368             *   no local definition. 
     369             */ 
     370            public Object lookupLocally(String symbol) { 
     371              return (null == symbols)? null : symbols.get(symbol); 
     372            } 
     373 
     374            /** 
     375             * Set the specified symbol's value to the specified value in this 
     376             * scope. 
     377             * 
     378             * @param symbol The unqualified symbol. 
     379             * @param value The value. 
     380             */ 
     381            public void define(String symbol, Object value) { 
     382              if (null == symbols) { 
     383                symbols = new HashMap<String, Object>(); 
     384              } 
     385              symbols.put(symbol, value); 
     386            } 
     387 
     388            /** 
     389             * Add the specified value to the specified symbol's values in 
     390             * this scope. 
     391             * 
     392             * @param symbol The unqualified symbol. 
     393             * @param value The value. 
     394             */ 
     395            @SuppressWarnings("unchecked") 
     396            public void addDefinition(String symbol, Object value) { 
     397              if (null == symbols) { 
     398                symbols = new HashMap<String, Object>(); 
     399              } 
     400 
     401              if (symbols.containsKey(symbol)) { 
     402                Object o = symbols.get(symbol); 
     403 
     404                if (o instanceof List) { 
     405                  ((List<Object>)o).add(value); 
     406 
     407                } else { 
     408                  List<Object> l = new ArrayList<Object>(); 
     409                  l.add(o); 
     410                  l.add(value); 
     411                  symbols.put(symbol, l); 
     412                } 
     413 
     414              } else { 
     415                symbols.put(symbol, value); 
     416              } 
     417            } 
     418 
     419            /** 
     420             * Undefine the specified unqualified symbol.  If the symbol is 
     421             * defined in this scope, this method removes all its values. 
     422             * 
     423             * @param symbol The unqualified symbol. 
     424             */ 
     425            public void undefine(String symbol) { 
     426              if (null != symbols) { 
     427                symbols.remove(symbol); 
     428              } 
     429            } 
     430 
     431            /** 
     432             * Qualify the specified unqualified symbol with this scope's 
     433             * name. 
     434             * 
     435             * @param symbol The unqualified symbol. 
     436             * @return The qualified symbol. 
     437             */ 
     438            public String qualify(String symbol) { 
     439              return Utilities.qualify(qName, symbol); 
     440            } 
     441 
     442            /** 
     443             * Dump the contents of this scope.  This method pretty prints the 
     444             * contents of this scope and all nested scopes with the specified 
     445             * printer.  If the printer is registered with a visitor, that 
     446             * visitor is used for formatting any node values. 
     447             * 
     448             * @param printer The printer, which need not be registered with a 
     449             *   visitor. 
     450             */ 
     451            public void dump(Printer printer) { 
     452              boolean hasVisitor = (null != printer.visitor()); 
     453 
     454              printer.indent().p('.').p(name).pln(" = {").incr(); 
     455 
     456              if (null != symbols) { 
     457                for (Map.Entry<String,Object> entry : symbols.entrySet()) { 
     458                  String symbol = entry.getKey(); 
     459                  Object value  = entry.getValue(); 
     460 
     461                  printer.indent().p(symbol).p(" = "); 
     462                  if (null == value) { 
     463                    printer.p("null"); 
     464                  } else if (hasVisitor && (value instanceof Node)) { 
     465                    printer.p((Node)value); 
     466                  } else if (value instanceof String) { 
     467                    printer.p('"').escape((String)value, Utilities.JAVA_ESCAPES).p('"'); 
     468                  } else { 
     469                    try { 
     470                      printer.p(value.toString()); 
     471                    } catch (final Exception e) { 
     472                      printer.p(value.getClass().getName() + "@?"); 
     473                    } 
     474                  } 
     475                  printer.pln(';'); 
     476 
     477                  PragmaScope nested = getNested(symbol); 
     478                  if (null != nested) { 
     479                    nested.dump(printer); 
     480                  } 
     481                } 
     482              } 
     483 
     484              if (null != pscopes) { 
     485                for (PragmaScope nested : pscopes.values()) { 
     486                  if ((null == symbols) || (! symbols.containsKey(nested.name))) { 
     487                    nested.dump(printer); 
     488                  } 
     489                } 
     490              } 
     491 
     492              printer.decr().indent().pln("};"); 
     493            } 
     494 
     495        } 
     496         
     497        // ========================================================================= 
     498          //Added for pragmaScope gestion 
     499          /** The root scope. */ 
     500          protected PragmaScope proot; 
     501           
     502          /** The current scope. */ 
     503          protected Scope pcurrent; 
     504 
     505          /** The fresh name count. */ 
     506          protected int pfreshNameCount; 
     507 
     508          /** The fresh identifier count. */ 
     509          protected int pfreshIdCount; 
     510 
     511          // ========================================================================= 
    6512 
    7513        public PragmaSymbolTable() { 
    8                 // TODO Auto-generated constructor stub 
    9514        } 
    10515 
    11516        public PragmaSymbolTable(String root) { 
    12517                super(root); 
    13                 // TODO Auto-generated constructor stub 
     518                this.proot = new PragmaScope(root); 
     519                //this.pcurrent = this.proot; 
     520                 
    14521        } 
    15522