001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo.query;
012:
013: /**
014: * A cast operation.
015: */
016: public class CastNode extends UnaryNode {
017:
018: public int brackets;
019: public String type;
020: public Class cls;
021:
022: public CastNode(Node child, int brackets, Object tp) {
023: super (child);
024: this .brackets = brackets;
025: if (tp instanceof Class)
026: cls = (Class) tp;
027: else
028: type = (String) tp;
029: }
030:
031: public String toString() {
032: StringBuffer s = new StringBuffer();
033: s.append(super .toString());
034: s.append(" (");
035: if (cls != null)
036: s.append(cls);
037: else
038: s.append(type);
039: s.append(')');
040: return s.toString();
041: }
042:
043: public Field visit(MemVisitor visitor, Object obj) {
044: return visitor.visitCastNode(this , obj);
045: }
046:
047: /**
048: * Convert us into a FieldNavNode with cast information.
049: */
050: protected void normalizeImp() {
051: super .normalizeImp();
052:
053: // convert this tree:
054: // CastNode (Address) [this]
055: // FieldNavNode (PolyRefHolder)data [toRaise]
056: // FieldNode data [toReplace]
057: // FieldNode city [toMove]
058: // SomeOtherNode [toKeep] (may be missing)
059:
060: // or this one (note that toRaise is missing):
061: // CastNode (Address) [this]
062: // FieldNode data [toReplace]
063: // FieldNode city [toMove]
064: // SomeOtherNode [toKeep] (may be missing)
065:
066: // into:
067: // FieldNavNode (PolyRefHolder)data [toRaise]
068: // FieldNavNode (Address)data [castFnn]
069: // FieldNode city [toMove]
070: // SomeOtherNode [toKeep] (if not null)
071:
072: if (next instanceof FieldNode || next instanceof FieldNavNode) {
073:
074: // find FieldNode to replace with FieldNavNode including cast
075: FieldNode toReplace = findFieldNode(childList);
076: if (toReplace == null)
077: return;
078: Node toMove = next;
079: Node toKeep = next.next;
080: Node toRaise = childList;
081:
082: // create FNN including cast from toReplace's field name
083: FieldNavNode castFnn = new FieldNavNode();
084: castFnn.cast = type;
085: castFnn.lexeme = toReplace.lexeme;
086:
087: // make toMove castFnn's only child
088: castFnn.childList = toMove;
089: toMove.parent = castFnn;
090: toMove.next = null;
091:
092: // make castFnn toReplace.parent's only child
093: toReplace.parent.childList = castFnn;
094: castFnn.parent = toReplace.parent;
095:
096: // if toRaise and toReplace are the same then raise castFnn
097: if (toRaise == toReplace)
098: toRaise = castFnn;
099:
100: // make toRaise and toKeep our parents first and second children
101: // removing us from the tree
102: parent.childList = toRaise;
103: toRaise.parent = parent;
104: toRaise.next = toKeep;
105: if (toKeep != null)
106: toKeep.parent = parent;
107: }
108: }
109:
110: /**
111: * Find the first FieldNode in tree at root following only the first
112: * child of each node down the tree. Returns null if none found.
113: */
114: private FieldNode findFieldNode(Node root) {
115: for (; root != null && !(root instanceof FieldNode); root = root.childList)
116: ;
117: return (FieldNode) root;
118: }
119:
120: public Object arrive(NodeVisitor v, Object msg) {
121: return v.arriveCastNode(this, msg);
122: }
123:
124: }
|