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 }