001    /* Copyright 2000, 2001, Compaq Computer Corporation */
002    
003    package javafe.parser;
004    
005    //alx: 
006    import javafe.Tool;
007    //alx-end
008    import javafe.ast.*;
009    import javafe.util.StackVector;
010    import javafe.util.ErrorSet;
011    import javafe.util.Location;
012    
013    /**
014     * Base class for Java parser; provides some basic parsing utilities.
015     *
016     * @see javafe.ast.ASTNode
017     * @see javafe.parser.ParseType
018     * @see javafe.parser.Parse
019     */
020    
021    public class ParseUtil
022    {
023        //alx: dw if to use the universe type system and with which level
024        //alx: TODO what specs for these fields
025        public int universeLevel=23;
026        public boolean useUniverses=false;
027        // used by parseModifiers() to remember universe modifiers
028        public int[] universeArray = {0,0};
029        //alx-end
030    
031        public ParseUtil() {
032            //@ set seqModifierPragma.elementType = \type(ModifierPragma);
033            //@ set seqModifierPragma.owner = this;
034            //alx: dw init universe vars
035            if (Tool.options!=null) {
036                    universeLevel=Tool.options.universeLevel;
037                    useUniverses=Tool.options.useUniverseTypeSystem;
038            }
039            //alx-end
040        }
041    
042    
043        //----------------------- Misc Helper Functions ----------------------------
044    
045        /** Raises a <TT>RuntimeException</TT> with the argument string. */
046    
047        // @ ensures false;
048        // UNUSED private static void fail(String m) { ErrorSet.fatal(m); }
049    
050        /** Raises a <TT>RuntimeException</TT> with the argument string
051            including a textual representation of the given source location. */
052        //@ requires loc != Location.NULL;
053        //@ ensures false;
054        public static void fail(int loc, String m) { ErrorSet.fatal(loc, m); }
055    
056        //@ requires loc != Location.NULL;
057        public static void error(int loc, String m) { ErrorSet.error(loc, m); }
058    
059        /** 
060         Takes an expected token from the input stream, 
061         calls <TT>fail</TT> on error.
062         */
063        //@ requires l != null && l.m_in != null;
064        //@ modifies l.ttype, l.auxVal, l.identifierVal;
065        //@ ensures \old(l.ttype)==expected;
066        public void expect(Lex l, int expected) {
067            if( l.ttype != expected ) 
068                fail(l.startingLoc,
069                     "Unexpected token '" + PrettyPrint.inst.toString(l.ttype) +
070                     "', expected '" + PrettyPrint.inst.toString(expected)+"'");
071            l.getNextToken();
072        }
073    
074        /**
075    
076         Converts operator tokens to corresponding AST tag.
077         Tokens INC and DEC get mapped to PREFIXINC and PREFIXDEC
078    
079         */
080    
081        int operatorTokenToTag(int token) {
082            // Right now we have the identity mapping.
083            return token;
084        }
085    
086    
087        /*------------------------ Modifiers -------------------------------*/
088    
089        //* Internal working storage for parse*Modifier* functions
090        //@ invariant seqModifierPragma.elementType == \type(ModifierPragma);
091        //@ invariant seqModifierPragma.owner == this;
092        protected final StackVector seqModifierPragma = new StackVector();
093    
094        /**
095         * Keyword at index i in this array corresponds to bit i in
096         * modifier bitset.  Thus PRIVATE is at index 1, ACC_PRIVATE =
097         * 1<<1.
098         * These are in the same bit order as the values in 
099         * java.lang.reflect.Modifier, and should remain that way, though
100         * I don't know if any code uses that fact (it might come in handy
101         * in reading class files, for example).
102         */
103        public static final int modifierKeywords[] = {
104            TagConstants.PUBLIC, TagConstants.PRIVATE, TagConstants.PROTECTED, 
105            TagConstants.STATIC, TagConstants.FINAL, 
106            TagConstants.SYNCHRONIZED, TagConstants.VOLATILE,
107            TagConstants.TRANSIENT, TagConstants.NATIVE, 
108            -1, // Don't consider 'interface' to be a modifier
109            TagConstants.ABSTRACT, TagConstants.STRICT
110        };
111    
112    
113        /**
114         * Parse a list of modifier pragmas.  Returns <code>null</code> if
115         * <code>l</code> does not point to a modifier pragma.  Otherwise,
116         * reads <code>l</code> until there are no more modifier pragmas and
117         * returns the resulting list.
118         */
119        //@ requires l.m_in != null;
120        public ModifierPragmaVec parseModifierPragmas(/*@ non_null @*/ Lex l) {
121            if (l.ttype != TagConstants.MODIFIERPRAGMA)
122                return null;
123    
124            seqModifierPragma.push();
125            do {
126                seqModifierPragma.addElement(l.auxVal);
127                l.getNextToken();
128            } while (l.ttype == TagConstants.MODIFIERPRAGMA);
129            return ModifierPragmaVec.popFromStackVector(seqModifierPragma);
130        }
131    
132        /**
133         * Parse a list of modifier pragmas and adds them to an existing
134         * <code>ModifierPragmaVec</code>.  If the existing
135         * <code>ModifierPragmaVec</code> was <code>null</code>, then it
136         * either returns <code>null</code> (if <code>l</code> does not point
137         * to a modifier pragma), or returns a new
138         * <code>ModifierPragmaVec</code>.
139         */
140        //@ requires l.m_in != null;
141        public ModifierPragmaVec parseMoreModifierPragmas(/*@ non_null @*/ Lex l, 
142                                                          ModifierPragmaVec orig)
143        {
144            ModifierPragmaVec modifierPragmas = parseModifierPragmas( l );
145            if (modifierPragmas == null)
146                return orig;
147            else if (orig == null)
148                return modifierPragmas;
149            else {
150                orig.append( modifierPragmas );
151                return orig;
152            }
153        }
154    
155        /** As a side effect, <code>parseModifiers</code> mutates this
156         value. */
157        public ModifierPragmaVec modifierPragmas;
158    
159    
160        /**
161         * Parse a list of modifiers.  Ensures no duplicate Java modifiers
162         * and only one of the access modifiers public, protected,
163         * private.  Return integer encoding the Java modifiers.
164         *
165         * <p> In addition to parsing Java modifiers, also handles modifier
166         * pragmas (anything with a ttype of TagConstants.MODIFIERPRAGMA).
167         * If no modifier pragmas are seen, sets
168         * <c>modifierPragmas</c> to <c>null</c>.  Otherwise, sets it to
169         * be the list of modifier pragmas seen in the course of parsing any
170         * Java modifiers.
171         *
172         * @see javafe.ast.Modifiers
173         */
174        //@ requires l.m_in != null;
175        //@ modifies modifierPragmas;
176        public int parseModifiers(/*@ non_null @*/ Lex l) {
177            boolean seenPragma = false;
178            //alx: dw next 3 variables are used for the universe type system
179            int nof_universeModifiers=0;
180            universeArray[0]=0;
181            universeArray[1]=0;
182    
183            int modifiers = Modifiers.NONE;
184    
185            getModifierLoop:
186            for(;;) {
187                if (l.ttype == TagConstants.MODIFIERPRAGMA) {
188                    //alx: dw
189                    //handle universe modifiers returned from PragmaParser
190                    if (universeLevel%2==0 && l.auxVal instanceof ModifierPragma) {
191                        int tag = ((ModifierPragma) l.auxVal).getTag();
192                        if (tag==TagConstants.PEER || 
193                            tag==TagConstants.REP || 
194                            tag==TagConstants.READONLY) {
195                            if (nof_universeModifiers>1) {
196                                if (universeLevel%5!=0)
197                                    ErrorSet.error(((ModifierPragma) l.auxVal).getStartLoc(),
198                                                   "too many Universe type modifiers");
199                                l.getNextToken();
200                                continue getModifierLoop;
201                            }
202                            universeArray[nof_universeModifiers++]=tag;
203                            l.getNextToken();
204                            continue getModifierLoop;
205                        }    
206                    }
207                    //alx-end
208                    if (! seenPragma) { 
209                            seqModifierPragma.push(); 
210                            seenPragma = true; 
211                    }
212                    seqModifierPragma.addElement(l.auxVal);
213                    l.getNextToken();
214                    continue getModifierLoop;
215                } else {
216                    //alx: dw handle universe modifiers that are used as keywords
217                    if (universeLevel%3==0 && (l.ttype==TagConstants.PEER || 
218                                               l.ttype==TagConstants.REP || 
219                                               l.ttype==TagConstants.READONLY)) {
220                        if (nof_universeModifiers>1) {
221                            if (universeLevel%5!=0)
222                                ErrorSet.error(l.startingLoc,
223                                               "too many Universe type modifiers");
224                            l.getNextToken();
225                            continue getModifierLoop;
226                        }
227                        universeArray[nof_universeModifiers++]=l.ttype;
228                        l.getNextToken();
229                        continue getModifierLoop;
230                    }
231                    //alx-end
232                    int i = getJavaModifier(l,modifiers);
233                    if (i != 0) {
234                        modifiers |= i;
235                        continue getModifierLoop;
236                    }
237                }
238    
239                // Next token is not a modifier
240                if (! seenPragma)
241                    modifierPragmas = null;
242                else
243                    modifierPragmas
244                        = ModifierPragmaVec.popFromStackVector(seqModifierPragma);
245                return modifiers;
246            }
247        }
248    
249        /** Checks if the next token is a Java modifier.  Returns 0
250            if it is not; returns an int with the modifier bit turned on
251            if it is.  Also issues an error if the modifier is already 
252            present in the modifiers argument (use 0 for this argument
253            to turn off these errors).
254            Note that the bit that is found is not ORed into the modifiers
255            int; you have to do that outside this call.
256            The Lex is advanced if a modifier is found.
257        */
258        public int getJavaModifier(Lex l, int modifiers) {
259            for( int i=0; i<modifierKeywords.length; i++ ) {
260                if( l.ttype == modifierKeywords[i] ) {
261                    // Token is modifier keyword 
262                    int modifierBit = 1<<i;
263                    if( (modifiers & modifierBit) != 0 ) {
264                        ErrorSet.caution(l.startingLoc, 
265                            "Duplicate occurrence of modifier '"
266                             +PrettyPrint.inst.toString(l.ttype)+"'");
267                    } else if( (modifiers & Modifiers.ACCESS_MODIFIERS) != 0 &&
268                        (modifierBit & Modifiers.ACCESS_MODIFIERS) != 0 ) {
269                        ErrorSet.error(l.startingLoc, 
270                             "Cannot have more than one of the access modifiers "+
271                             "public, protected, private");
272                    }
273                    l.getNextToken();
274                    return modifierBit;
275                }
276            }
277            return 0;
278        }
279    
280        public boolean isJavaModifier(int ttype) {
281            for( int i=0; i<modifierKeywords.length; i++ ) {
282                if( ttype == modifierKeywords[i] ) return true;
283            }
284            return false;
285        }
286    
287        static public String arrayToString(Object[] a, String sep) {
288            if (a==null || a.length == 0) return "";
289            else {
290                    StringBuffer sb = new StringBuffer();
291                    sb.append(a[0].toString());
292                    for (int i=1; i<a.length; ++i) {
293                        sb.append(sep);
294                        sb.append(a[i].toString());
295                    }
296                    return sb.toString();
297            }
298        }
299    
300        //alx: dw parses universes and rejects all other modifiers!!
301        //TODO: what other specs?
302        public void parseUniverses(/*@ non_null @*/ Lex l) {
303            int loc = l.startingLoc;
304            int jmods = parseModifiers(l);
305            if (jmods!=0)
306                    ErrorSet.error(loc,"no java modifiers allowed");
307            if (modifierPragmas!=null && modifierPragmas.size()!=0)
308                    ErrorSet.error(loc,"only Universe type modifiers allowed");
309        }
310        //alx-end
311        
312        //alx: dw using decorations to save the universe modifiers
313        private static ASTDecoration universeDecoration =
314            new ASTDecoration("universeDecoration");
315        //alx-end
316        
317        //alx: dw sets the universeDecoration of node i
318        //TODO: what other specs?
319        public static /*@ non_null @*/ ASTNode setUniverse(
320                       /*@ non_null @*/ ASTNode i, 
321                       int u) {
322            universeDecoration.set(i,new Integer(u));
323            return i;
324        }
325        //alx-end
326        
327        //alx: dw sets the universe modifier and array element modifier of i to
328        //   the values in the array. with error-checking!
329        //TODO: what other specs?
330        public static /*@ non_null @*/ ASTNode setUniverse(
331                                          /*@ non_null @*/ ASTNode i, 
332                                          int[] a, 
333                                          /*@ non_null @*/ Type t, int loc) {
334            int tag = t.getTag();
335            boolean reportErrors=Tool.options!=null && 
336                                 Tool.options.universeLevel%5!=0;
337            if (a!=null && !(tag==TagConstants.ARRAYTYPE)) {
338                if (t instanceof PrimitiveType) {
339                    if (a[0]!=0 && reportErrors)
340                        ErrorSet.error(loc,
341                               "primitive types must not have Universe modifiers");
342                    return i;
343                }
344                if (a[0]!=0)
345                    universeDecoration.set(i,new Integer(a[0]));
346                else
347                    universeDecoration.set(i,new Integer(TagConstants.IMPL_PEER));
348                if (a[1]!=0 && reportErrors)
349                    ErrorSet.error(loc,
350                         "only array types can have 2 Universe modifiers");
351            } 
352            else if (a!=null && tag==TagConstants.ARRAYTYPE) {
353                ArrayType at = (ArrayType ) t;
354                //primitive types need only the array modifier
355                if (at.elemType instanceof PrimitiveType) {
356                    if (a[0]==0) {
357                        universeDecoration.set(i,
358                                             new Integer(TagConstants.IMPL_PEER));
359                        return i;
360                    }
361                    else if (a[1]!=0 && reportErrors) 
362                        ErrorSet.error(loc,
363                             "only one Universe modifier allowed for "+
364                             "arrays of primitve type");
365                    universeDecoration.set(i,new Integer(a[0]));
366                } 
367                else {
368                    if (a[0]==0) {
369                        universeDecoration.set(i,
370                                          new Integer(TagConstants.IMPL_PEER));
371                        elementUniverseDecoration.set(i,
372                                          new Integer(TagConstants.IMPL_PEER));
373                        return i;
374                    }
375                    else if(a[1]==0) {
376                        if (a[0]==TagConstants.REP) {
377                            if (reportErrors)
378                                ErrorSet.error(loc,
379                                     "rep not allowed for array elements");
380                            a[0]=TagConstants.IMPL_PEER;
381                        }
382                        universeDecoration.set(i,
383                                new Integer(TagConstants.IMPL_PEER));
384                        elementUniverseDecoration.set(i,new Integer(a[0]));
385                    } else {
386                        if (a[1]==TagConstants.REP) {
387                            if (reportErrors)
388                                ErrorSet.error(loc,
389                                     "rep not allowed for array elements");
390                            a[1]=TagConstants.IMPL_PEER;
391                        }
392                        universeDecoration.set(i,new Integer(a[0]));
393                        elementUniverseDecoration.set(i,new Integer(a[1]));
394                    }
395                }
396            }
397            if (reportErrors && getUniverse(i)==TagConstants.READONLY &&
398                (i.getTag()==TagConstants.NEWINSTANCEEXPR
399                 || i.getTag()==TagConstants.NEWARRAYEXPR))
400                ErrorSet.error(i.getStartLoc(),
401                     "readonly not allowed for new expression, except for "+
402                     "array element modifier");
403            return i;
404        }
405        //alx-end
406        
407        //alx: dw sets the universe modifier and array element modifier of i to
408        //   the values in the array. with error-checking!
409        //TODO: what other specs?
410        /*@ 
411          @ requires i.type !=null;
412          @*/
413        public static /*@ non_null @*/ ASTNode setUniverse(
414                                          /*@ non_null @*/ GenericVarDecl i, 
415                                          int[] a) {
416            return setUniverse(i,a,i.type,i.getStartLoc());
417        }
418        
419        //alx: dw gets the universeDecoration of node i
420        //TODO: what other specs?
421        public static int getUniverse(/*@ non_null @*/ ASTNode i) {
422            Object o = universeDecoration.get(i);
423            if (o instanceof Integer)
424                    return ((Integer) o).intValue();
425            return 0;
426        }
427        //alx-end
428        
429        //alx: dw using decorations for array element universe modifier
430        //TODO: what specs?
431        private static ASTDecoration elementUniverseDecoration
432                    = new ASTDecoration("elementUniverseDecoration");
433        //alx-end
434        
435        //alx: dw sets the elementUniverseDecoration of node i
436        //TODO: what other specs?
437        public static /*@ non_null @*/ ASTNode setElementUniverse(
438                                                 /*@ non_null @*/ ASTNode i, 
439                                                 int u) {
440            elementUniverseDecoration.set(i,new Integer(u));
441            return i;
442        }
443        //alx-end
444        
445        //alx: dw gets the elementUniverseDecoration of node i
446        //TODO: what other specs?
447        public static int getElementUniverse(/*@ non_null @*/ ASTNode i) {
448            Object o = elementUniverseDecoration.get(i);
449            if (o instanceof Integer)
450                    return ((Integer) o).intValue();
451            return 0;
452        }
453        //alx-end
454    }