KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > jga > parser > ParserContext


1 // ============================================================================
2
// $Id: ParserContext.java,v 1.5 2006/12/16 16:48:57 davidahall Exp $
3
// Copyright (c) 2005 David A. Hall
4
// ============================================================================
5
// The contents of this file are subject to the Common Development and
6
// Distribution License (CDDL), Version 1.0 (the License); you may not use this
7
// file except in compliance with the License. You should have received a copy
8
// of the the License along with this file: if not, a copy of the License is
9
// available from Sun Microsystems, Inc.
10
//
11
// http://www.sun.com/cddl/cddl.html
12
//
13
// From time to time, the license steward (initially Sun Microsystems, Inc.) may
14
// publish revised and/or new versions of the License. You may not use,
15
// distribute, or otherwise make this file available under subsequent versions
16
// of the License.
17
//
18
// Alternatively, the contents of this file may be used under the terms of the
19
// GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
20
// case the provisions of the LGPL are applicable instead of those above. If you
21
// wish to allow use of your version of this file only under the terms of the
22
// LGPL, and not to allow others to use your version of this file under the
23
// terms of the CDDL, indicate your decision by deleting the provisions above
24
// and replace them with the notice and other provisions required by the LGPL.
25
// If you do not delete the provisions above, a recipient may use your version
26
// of this file under the terms of either the CDDL or the LGPL.
27
//
28
// This library is distributed in the hope that it will be useful,
29
// but WITHOUT ANY WARRANTY; without even the implied warranty of
30
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
31
// ============================================================================
32

33 package net.sf.jga.parser;
34
35 import java.lang.reflect.Field JavaDoc;
36 import java.lang.reflect.Method JavaDoc;
37 import java.lang.reflect.Modifier JavaDoc;
38 import java.math.BigDecimal JavaDoc;
39 import java.math.BigInteger JavaDoc;
40 import java.text.MessageFormat JavaDoc;
41 import java.util.ArrayList JavaDoc;
42 import java.util.HashMap JavaDoc;
43 import java.util.List JavaDoc;
44 import java.util.Map JavaDoc;
45 import net.sf.jga.fn.UnaryFunctor;
46 import net.sf.jga.fn.arithmetic.ValueOf;
47
48 /**
49  * Configuration settings for a JFXGParser.
50  * <p>
51  * Copyright &copy; 2005 David A. Hall
52  */

53
54 class ParserContext {
55     // Maps the argument names to their declared classes (declared to the entry point that
56
// defines them: the names are bound to the types given to the parseGenerator, parseUnary,
57
// and parseBinary methods)
58
private Map JavaDoc<String JavaDoc,Class JavaDoc> _arguments = new HashMap JavaDoc<String JavaDoc,Class JavaDoc>();
59     
60     // Imported classes, keyed by the classname within the package (or an alias)
61
private Map JavaDoc<String JavaDoc,Class JavaDoc> _imports = new HashMap JavaDoc<String JavaDoc,Class JavaDoc>();
62
63     // Imported packages
64
private List JavaDoc<String JavaDoc> _packages = new ArrayList JavaDoc<String JavaDoc>();
65     
66     // Imported static methods, keyed by the method name (or an alias). Multiple methods
67
// may be keyed to the same name
68
private Map JavaDoc<String JavaDoc,List JavaDoc<Method JavaDoc>> _methods = new HashMap JavaDoc<String JavaDoc,List JavaDoc<Method JavaDoc>>();
69     
70     // Imported static members.
71
private Map JavaDoc<String JavaDoc,Field JavaDoc> _fields = new HashMap JavaDoc<String JavaDoc,Field JavaDoc>();
72     
73     // The object to which "this" refers (the parser won't reference itself directly)
74
private Object JavaDoc _thisObj;
75
76     // True if decimal strings without a 'D' or 'F' are to be interpreted as BigDecimal
77
// constants
78
private boolean _undecoratedDecimal;
79
80     ParserContext() {
81         initializePromotionRules();
82     }
83     
84     /**
85      * Returns a copy of this context.
86      */

87     ParserContext copy() {
88         ParserContext peer = new ParserContext();
89         peer._arguments.putAll(_arguments);
90         peer._imports.putAll(_imports);
91         peer._methods.putAll(_methods);
92         peer._fields.putAll(_fields);
93
94         peer._packages.addAll(_packages);
95
96         peer._thisObj = _thisObj;
97         peer._undecoratedDecimal = _undecoratedDecimal;
98
99         for (Class JavaDoc fromtype : _promotionRules.keySet()) {
100             HashMap JavaDoc<Class JavaDoc,UnaryFunctor> ruleset = _promotionRules.get(fromtype);
101             for (Class JavaDoc totype : ruleset.keySet()) {
102                 UnaryFunctor fn = ruleset.get(totype);
103                 peer.addPromotionRule(fromtype, totype, fn);
104             }
105         }
106         
107         return peer;
108     }
109
110     /**
111      * Declares a named argument to the functor being built, and its type.
112      */

113     public void declareArgument(String JavaDoc argName, Class JavaDoc argType) {
114         _arguments.put(argName, argType);
115     }
116
117     /**
118      * Returns the type of the named argument, or null if the name is unrecognized
119      */

120     public Class JavaDoc getTypeForName(String JavaDoc name) {
121         return _arguments.get(name);
122     }
123     
124     
125     /**
126      * Imports the given class into the parser. The class will not need to be
127      * fully qualified for use in expressions. This will replace any existing
128      * imported class that happens to have the same name.
129      */

130     public void importClass(Class JavaDoc clasz) {
131         importClass(ParserUtils.getSimpleName(clasz), clasz);
132     }
133
134     
135     /**
136      * Imports the given class into the parser under the given alias. The alias
137      * may be used in place of the fully qualified name of the class hereafter.
138      * This will replace any existing imported class associated with the alias.
139      */

140     public void importClass(String JavaDoc alias, Class JavaDoc clasz) {
141         if (alias != null && clasz != null)
142             _imports.put(alias, clasz);
143     }
144
145
146     /**
147      * Removes information about the class imported under the given name.
148      */

149     public void deportClass(String JavaDoc alias) {
150         if (alias != null)
151             _imports.remove(alias);
152     }
153
154     /**
155      * Returns the class associated with the given alias
156      */

157     public Class JavaDoc getImportedClass(String JavaDoc alias) {
158         Class JavaDoc klass = _imports.get(alias);
159         if (klass != null)
160             return klass;
161
162         List JavaDoc<Class JavaDoc> potentials = new ArrayList JavaDoc<Class JavaDoc>();
163         for (String JavaDoc pkgName : _packages) {
164             try {
165                 potentials.add(Class.forName(pkgName+"."+alias));
166             }
167             catch (Exception JavaDoc x) {
168                 // There's no way to know that a class exists, other than to try and
169
// load it. Exceptions for flow control are the only option, here.
170
}
171         }
172
173         if (potentials.size() == 1) {
174             return potentials.get(0);
175         }
176
177         return null;
178     }
179
180     
181     /**
182      * Imports all classes in the given package into the parser.
183      */

184     public void importPackage(String JavaDoc pkgName) {
185         if ( ! _packages.contains(pkgName)) {
186             _packages.add(pkgName);
187         }
188     }
189
190     
191     /**
192      * Removes information about the package imported under the given name.
193      */

194     public void deportPackage(String JavaDoc pkgName) {
195         _packages.remove(pkgName);
196     }
197     
198     
199     /**
200      * Imports all of the static public methods and members in the given class.
201      */

202     public void importStatics(Class JavaDoc clasz) {
203         // First, do the fields
204
Field JavaDoc[] fields = clasz.getFields();
205         for (int i = 0; i < fields.length; ++i) {
206             if (Modifier.isStatic(fields[i].getModifiers()))
207                 importField(fields[i]);
208         }
209
210         // next, do the methods
211
Method JavaDoc[] methods = clasz.getMethods();
212         for (int i= 0; i < methods.length; ++i) {
213             if (Modifier.isStatic(methods[i].getModifiers()))
214                 importMethod(methods[i]);
215         }
216     }
217
218     
219     /**
220      * Imports the given static member. The member will not need to be qualified
221      * with its classname for use in expressions.
222      * @throws java.lang.NoSuchFieldException if the named field does not exist
223      * @throws java.lang.IllegalArgumentException if the named field is not static
224      */

225     public void importField(Class JavaDoc clasz, String JavaDoc name) throws NoSuchFieldException JavaDoc {
226         importField(clasz.getField(name));
227     }
228
229     /**
230      * Imports the given static member. The member will not need to be qualified
231      * with its classname for use in expressions.
232      * @throws java.lang.IllegalArgumentException if the field is not static
233      */

234     public void importField(Field JavaDoc field) throws IllegalArgumentException JavaDoc {
235         if (! Modifier.isStatic(field.getModifiers())) {
236             String JavaDoc msg = "Cannot import non-static field {0}";
237             throw new IllegalArgumentException JavaDoc(MessageFormat.format(msg, new Object JavaDoc[]{ field }));
238         }
239                                                
240         _fields.put(field.getName(), field);
241     }
242
243     /**
244      * Returns the imported field with the given name, or null if no such field has
245      * been imported.
246      */

247     public Field JavaDoc getImportedField(String JavaDoc name) {
248         return _fields.get(name);
249     }
250     
251     /**
252      * Imports the given static method(s).
253      * @throws java.lang.NoSuchMethodException if the named method does not exist, or if
254      * it/they is/are not static
255      */

256     public void importMethod(Class JavaDoc clasz, String JavaDoc name) throws NoSuchMethodException JavaDoc {
257         Method JavaDoc[] methods = clasz.getMethods();
258         int numImported = 0;
259         for (int i= 0; i < methods.length; ++i) {
260             if (name.equals(methods[i].getName()) && Modifier.isStatic(methods[i].getModifiers())) {
261                 importMethod(name, methods[i]);
262                 ++numImported;
263             }
264         }
265
266         if (numImported == 0) {
267             String JavaDoc msg = "No non-static method {0} found in class {1}";
268             Object JavaDoc[] args = new Object JavaDoc[] {name, clasz.getName()};
269             throw new NoSuchMethodException JavaDoc(MessageFormat.format(msg, args));
270         }
271     }
272
273     /**
274      * Imports a static method into the parser. The method will not need to be
275      * qualified with its classname for use in expressions. Multiple methods
276      * may be imported with the same name: the first best fit will be used when
277      * the method name is used.
278      * @throws java.lang.NoSuchMethodException if the named method does not exist
279      * @throws java.lang.IllegalArgumentException if the named method is not static
280      */

281     public void importMethod(Method JavaDoc meth) {
282         importMethod(meth.getName(), meth);
283     }
284     
285     /**
286      * Imports a static method into the parser under the given name. The method
287      * will not need to be qualified with its classname for use in expressions.
288      * Multiple methods may be imported with the same name: the first best fit
289      * will be used when the method name is used.
290      * @throws java.lang.IllegalArgumentException if the method is not static
291      */

292     public void importMethod(String JavaDoc name, Method JavaDoc meth) {
293         if (! Modifier.isStatic(meth.getModifiers())) {
294             String JavaDoc msg = "Cannot import non-static method {0}";
295             throw new IllegalArgumentException JavaDoc(MessageFormat.format(msg, new Object JavaDoc[]{ meth }));
296         }
297                                                
298         List JavaDoc<Method JavaDoc> methodList = _methods.get(name);
299         if (methodList == null) {
300             methodList = new ArrayList JavaDoc<Method JavaDoc>();
301             _methods.put(name, methodList);
302         }
303         methodList.add(meth);
304     }
305
306
307     /**
308      * Returns a list of methods with the given name
309      */

310     public Method JavaDoc[] getImportedMethods(String JavaDoc name) {
311         List JavaDoc<Method JavaDoc> methodList = _methods.get(name);
312         if (methodList == null)
313             return new Method JavaDoc[0];
314         else
315             return methodList.toArray(new Method JavaDoc[0]);
316     }
317     
318
319     /**
320      * Binds the object to which 'this' refers
321      */

322     public void bindThis(Object JavaDoc thisBinding) {
323         _thisObj = thisBinding;
324     }
325
326     
327     /**
328      * Returns the current object to which 'this' refers
329      */

330     protected Object JavaDoc getBoundObject() {
331         return _thisObj;
332     }
333     
334     
335     /**
336      * Enables/Disables the interpretation of undecorated decimal literals
337      * as BigDecimals. When true, an undecorated number containing a
338      * decimal, for example <tt>1.50</tt> is interpreted as a BigDecimal
339      * literal. When false, the same token is interpreted as a Double, as
340      * is the case in standard java
341      */

342     public void setUndecoratedDecimal(boolean flag) { _undecoratedDecimal = flag; }
343
344     
345     /**
346      * When true, an undecorated number containing a
347      * decimal, for example <tt>1.50</tt> is interpreted as a BigDecimal
348      * literal. When false, the same token is interpreted as a Double, as
349      * is the case in standard java
350      */

351     public boolean isUndecoratedDecimal() { return _undecoratedDecimal; }
352
353
354     /**
355      * Registers a type-coercion rule that will promote values of the from type to
356      * values of the to type for use in expressions.
357      */

358     public void addPromotionRule(Class JavaDoc fromType, Class JavaDoc toType, UnaryFunctor converter) {
359         HashMap JavaDoc<Class JavaDoc, UnaryFunctor> ruleset = _promotionRules.get(fromType);
360         if (ruleset == null) {
361             ruleset = new HashMap JavaDoc<Class JavaDoc, UnaryFunctor>();
362             _promotionRules.put(fromType, ruleset);
363         }
364
365         ruleset.put(toType, converter);
366     }
367
368     /**
369      * Removes the type-coercion rule (if any) that would have promoted values of the
370      * from type to values of the to type for use in expressions.
371      */

372     public void removePromotionRule(Class JavaDoc fromType, Class JavaDoc toType) {
373         HashMap JavaDoc<Class JavaDoc, UnaryFunctor> ruleset = _promotionRules.get(fromType);
374         if (ruleset != null)
375             ruleset.remove(toType);
376     }
377
378     /**
379      * Returns a type-coercion rule that will promote values of the from type to
380      * values of the to type for use in expressions, if any such rule exists.
381      * Returns null if no such rule exists.
382      */

383     public UnaryFunctor getPromotionRule(Class JavaDoc fromType, Class JavaDoc toType) {
384         HashMap JavaDoc<Class JavaDoc, UnaryFunctor> ruleset = _promotionRules.get(fromType);
385         if (ruleset == null)
386             return null;
387         
388         return ruleset.get(toType);
389     }
390
391     
392     private HashMap JavaDoc<Class JavaDoc, HashMap JavaDoc<Class JavaDoc, UnaryFunctor>> _promotionRules = new HashMap JavaDoc();
393
394     private UnaryFunctor toShort = new ValueOf(Short JavaDoc.class);
395     
396     private UnaryFunctor toInteger = new ValueOf(Integer JavaDoc.class);
397     private UnaryFunctor toLong = new ValueOf(Long JavaDoc.class);
398     private UnaryFunctor toFloat = new ValueOf(Float JavaDoc.class);
399     private UnaryFunctor toDouble = new ValueOf(Double JavaDoc.class);
400     private UnaryFunctor toDecimal = new ValueOf(BigDecimal JavaDoc.class);
401     private UnaryFunctor toBigInt = new ValueOf(BigInteger JavaDoc.class);
402
403     private void initializePromotionRules() {
404         addPromotionRule(Byte JavaDoc.class, Short JavaDoc.class, toShort);
405         addPromotionRule(Byte JavaDoc.class, Integer JavaDoc.class, toInteger);
406         addPromotionRule(Byte JavaDoc.class, Long JavaDoc.class, toLong);
407         addPromotionRule(Byte JavaDoc.class, BigInteger JavaDoc.class,toBigInt);
408         addPromotionRule(Byte JavaDoc.class, Double JavaDoc.class, toDouble);
409         addPromotionRule(Byte JavaDoc.class, Float JavaDoc.class, toFloat);
410         addPromotionRule(Byte JavaDoc.class, BigDecimal JavaDoc.class,toDecimal);
411         
412         addPromotionRule(Short JavaDoc.class, Integer JavaDoc.class, toInteger);
413         addPromotionRule(Short JavaDoc.class, Long JavaDoc.class, toLong);
414         addPromotionRule(Short JavaDoc.class, BigInteger JavaDoc.class,toBigInt);
415         addPromotionRule(Short JavaDoc.class, Double JavaDoc.class, toDouble);
416         addPromotionRule(Short JavaDoc.class, Float JavaDoc.class, toFloat);
417         addPromotionRule(Short JavaDoc.class, BigDecimal JavaDoc.class,toDecimal);
418         
419         addPromotionRule(Integer JavaDoc.class, Long JavaDoc.class, toLong);
420         addPromotionRule(Integer JavaDoc.class, BigInteger JavaDoc.class,toBigInt);
421         addPromotionRule(Integer JavaDoc.class, Float JavaDoc.class, toFloat);
422         addPromotionRule(Integer JavaDoc.class, Double JavaDoc.class, toDouble);
423         addPromotionRule(Integer JavaDoc.class, BigDecimal JavaDoc.class,toDecimal);
424         
425         addPromotionRule(Long JavaDoc.class, BigInteger JavaDoc.class,toBigInt);
426         addPromotionRule(Long JavaDoc.class, Float JavaDoc.class, toFloat);
427         addPromotionRule(Long JavaDoc.class, Double JavaDoc.class, toDouble);
428         addPromotionRule(Long JavaDoc.class, BigDecimal JavaDoc.class,toDecimal);
429         
430         addPromotionRule(BigInteger JavaDoc.class,Float JavaDoc.class, toFloat);
431         addPromotionRule(BigInteger JavaDoc.class,Double JavaDoc.class, toDouble);
432         addPromotionRule(BigInteger JavaDoc.class,BigDecimal JavaDoc.class,toDecimal);
433         
434         addPromotionRule(Float JavaDoc.class, Double JavaDoc.class, toDouble);
435         addPromotionRule(Float JavaDoc.class, BigDecimal JavaDoc.class,toDecimal);
436         
437         addPromotionRule(Double JavaDoc.class, BigDecimal JavaDoc.class,toDecimal);
438     }
439 }
440
Popular Tags