001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.lib.contract.lang.op.constant;
028:
029: import org.cougaar.lib.contract.lang.*;
030: import org.cougaar.lib.contract.lang.cache.ClassCache;
031: import org.cougaar.lib.contract.lang.op.OpBuilder;
032: import org.cougaar.lib.contract.lang.op.OpCodes;
033:
034: /**
035: * Holds an Object constant, as set by the parser.
036: * <p>
037: * <pre>
038: * Considered allowing the user to "quote" a literal <code>Op</code>,
039: * for example:
040: * Look for a null element in a List using "existsMethod(Op)"
041: * (getList (existsMethod (quote (isNull))))
042: * However, this would make it awkward to create a bytecode translator,
043: * since the sub-<code>Op</code> would need to exist as a separate
044: * <code>Op</code> instance.
045: * <p>
046: * One can still get this effect by using <code>GetOp</code>, for example:
047: * op1 = (getList (existsMethod (get "myElemChecker")))
048: * op2 = (isNull)
049: * op1.setConst("myElemChecker", op2);
050: * but this means that "all", "empty", and "exists" need to remain as
051: * language-internal <code>Op</code>s.
052: * </pre>
053: */
054: public final class ConstantOp extends OpImpl {
055:
056: public final Class clazz;
057: public final Object val;
058:
059: /**
060: * Create unset constant -- will expect parsed Class and Value arguments.
061: */
062: public ConstantOp() {
063: // unset
064: this .clazz = null;
065: this .val = null;
066: }
067:
068: /**
069: * Create String constant.
070: */
071: public ConstantOp(final String sval) {
072: this .clazz = String.class;
073: this .val = sval;
074: }
075:
076: /**
077: * Create String/primitive constant.
078: */
079: public ConstantOp(final String sclass, final String sval) {
080: if (sclass == null) {
081: this .clazz = String.class;
082: this .val = sval;
083: return;
084: }
085: try {
086: switch ((sclass.length() > 0) ? sclass.charAt(0) : '?') {
087: case 'b':
088: if (sclass.equals("boolean")) {
089: this .clazz = Boolean.TYPE;
090: this .val = new Boolean(sval);
091: return;
092: } else if (sclass.equals("byte")) {
093: this .clazz = Byte.TYPE;
094: this .val = new Byte(sval);
095: return;
096: }
097: break;
098: case 'c':
099: if (sclass.equals("char")) {
100: if ((sval != null) && (sval.length() == 1)) {
101: this .clazz = Character.TYPE;
102: this .val = new Character(sval.charAt(0));
103: return;
104: } else {
105: throw new NumberFormatException("Bad Char!");
106: }
107: }
108: break;
109: case 's':
110: if (sclass.equals("short")) {
111: this .clazz = Short.TYPE;
112: this .val = new Short(sval);
113: return;
114: } else if (sclass.equals("string")) {
115: this .clazz = String.class;
116: this .val = sval;
117: return;
118: }
119: break;
120: case 'i':
121: if (sclass.equals("int")) {
122: this .clazz = Integer.TYPE;
123: this .val = new Integer(sval);
124: return;
125: }
126: break;
127: case 'l':
128: if (sclass.equals("long")) {
129: this .clazz = Long.TYPE;
130: this .val = new Long(sval);
131: return;
132: }
133: break;
134: case 'f':
135: if (sclass.equals("float")) {
136: this .clazz = Float.TYPE;
137: this .val = new Float(sval);
138: return;
139: }
140: break;
141: case 'd':
142: if (sclass.equals("double")) {
143: this .clazz = Double.TYPE;
144: this .val = new Double(sval);
145: return;
146: }
147: break;
148: case 'n':
149: if (sclass.equals("null")) {
150: // null followed by classname -- switched order to differentiate
151: // "a null String" v.s. "a String with value \"null\"".
152: Class cl = ClassCache.lookup(sval);
153: if (cl != null) {
154: this .clazz = cl;
155: this .val = null;
156: return;
157: } else {
158: throw new IllegalArgumentException(
159: "Unknown \"null\" class " + sval);
160: }
161: }
162: case 'j':
163: if (sclass.equals("java.lang.String")) {
164: this .clazz = String.class;
165: this .val = sval;
166: return;
167: }
168: break;
169: case 'S':
170: if (sclass.equals("String")) {
171: this .clazz = String.class;
172: this .val = sval;
173: return;
174: }
175: break;
176: default:
177: break;
178: }
179: } catch (NumberFormatException eBadNumber) {
180: throw new IllegalArgumentException(
181: "Incompatible type for constant. "
182: + "Can't convert " + sval + " to " + sclass
183: + ".");
184: }
185: throw new IllegalArgumentException("Invalid Constant ("
186: + sclass + ", " + sval
187: + ") is not a String or primitive");
188: }
189:
190: /**
191: * Create String/primitive constant.
192: */
193: public ConstantOp(final Class clazz, final Object val) {
194: if (clazz == null) {
195: throw new IllegalArgumentException("\""
196: + OpCodes.CONSTANT_NAME
197: + "\" expecting non-Null Class");
198: } else if ((clazz.isPrimitive()) && (val == null)) {
199: throw new IllegalArgumentException("\""
200: + OpCodes.CONSTANT_NAME
201: + "\" expecting non-Null primitive value");
202: }
203: this .clazz = clazz;
204: this .val = val;
205: }
206:
207: public final int getID() {
208: return OpCodes.CONSTANT_ID;
209: }
210:
211: public final Op parse(final OpParser p) throws ParseException {
212: Op u1 = p.nextOp();
213: if (u1 == null) {
214: // check for value
215: if (this .clazz == null) {
216: throw new ParseException("\"" + OpCodes.CONSTANT_NAME
217: + "\" expecting Class and value arguments");
218: }
219:
220: // use class as given
221: p.setTypeList(clazz);
222: return this ;
223: } else {
224: // check for value
225: if (this .clazz != null) {
226: throw new ParseException("\"" + OpCodes.CONSTANT_NAME
227: + "\" already has a type: " + clazz
228: + " value: " + val);
229: }
230:
231: // take constant string type
232: Object sclass;
233: if (u1.getID() != OpCodes.CONSTANT_ID) {
234: throw new ParseException("\"" + OpCodes.CONSTANT_NAME
235: + "\" expecting \"class\" argument, not "
236: + u1.getClass().toString());
237: } else if (!((sclass = ((ConstantOp) u1).val) instanceof String)) {
238: throw new ParseException("\""
239: + OpCodes.CONSTANT_NAME
240: + "\" expecting String \"class\", not "
241: + ((sclass != null) ? sclass.getClass()
242: .toString() : "null"));
243: }
244:
245: // take constant string value
246: Object svalue;
247: Op u2 = p.nextOp();
248: if (u2 == null) {
249: // assume String
250: svalue = sclass;
251: sclass = "String";
252: } else {
253: if (u2.getID() != OpCodes.CONSTANT_ID) {
254: throw new ParseException("\""
255: + OpCodes.CONSTANT_NAME
256: + "\" expecting \"value\" argument, not "
257: + u2.getClass().toString());
258: } else if (!((svalue = ((ConstantOp) u2).val) instanceof String)) {
259: throw new ParseException("\""
260: + OpCodes.CONSTANT_NAME
261: + "\" expecting String \"value\", not "
262: + ((svalue != null) ? svalue.getClass()
263: .toString() : "null"));
264: }
265:
266: // make sure it's the last argument
267: Op u3 = p.nextOp();
268: if (u3 != null) {
269: throw new ParseException("\""
270: + OpCodes.CONSTANT_NAME
271: + "\" expecting two arguments, "
272: + "but given additional "
273: + u3.getClass().toString());
274: }
275: }
276:
277: // replace with given constant
278: return new ConstantOp((String) sclass, (String) svalue);
279: }
280: }
281:
282: public final boolean isReturnBoolean() {
283: return (clazz == Boolean.TYPE);
284: }
285:
286: public final Class getReturnClass() {
287: return clazz;
288: }
289:
290: public final boolean execute(final Object o) {
291: // ignore o
292: return ((Boolean) val).booleanValue();
293: }
294:
295: public final Object operate(final Object o) {
296: // ignore o
297: return val;
298: }
299:
300: public final void accept(TreeVisitor visitor) {
301: if (clazz == String.class) {
302: if (val != null) {
303: // (const ("val"))
304: visitor.visitConstant(null, (String) val);
305: } else {
306: // (const ("null") ("java.lang.String"))
307: visitor.visitConstant("null", "java.lang.String");
308: }
309: } else if (clazz == null) {
310: // likely in the middle of parsing
311: visitor.visitConstant("?", "?");
312: } else if (clazz.isPrimitive()) {
313: // (const ("clazz") ("val"))
314: visitor.visitConstant(clazz.getName(), val.toString());
315: } else if (val == null) {
316: // (const ("null") ("clazz"))
317: visitor.visitConstant("null", clazz.getName());
318: } else {
319: // how did this get parsed?
320: throw new IllegalArgumentException(
321: "Unknown constant class: " + clazz.getName());
322: }
323: }
324: }
|