NodeSetType.java revision 628:2bfaf29cc90b
184124Sdfr/*
284124Sdfr * reserved comment block
384124Sdfr * DO NOT REMOVE OR ALTER!
484124Sdfr */
584124Sdfr/*
684124Sdfr * Copyright 2001-2004 The Apache Software Foundation.
784124Sdfr *
884124Sdfr * Licensed under the Apache License, Version 2.0 (the "License");
984124Sdfr * you may not use this file except in compliance with the License.
1084124Sdfr * You may obtain a copy of the License at
1184124Sdfr *
1284124Sdfr *     http://www.apache.org/licenses/LICENSE-2.0
1384124Sdfr *
1484124Sdfr * Unless required by applicable law or agreed to in writing, software
1584124Sdfr * distributed under the License is distributed on an "AS IS" BASIS,
1684124Sdfr * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1784124Sdfr * See the License for the specific language governing permissions and
1884124Sdfr * limitations under the License.
1984124Sdfr */
2084124Sdfr/*
2184124Sdfr * $Id: NodeSetType.java,v 1.2.4.1 2005/09/05 11:21:45 pvedula Exp $
2284124Sdfr */
2384124Sdfr
2484124Sdfrpackage com.sun.org.apache.xalan.internal.xsltc.compiler.util;
2584124Sdfr
2684124Sdfrimport com.sun.org.apache.bcel.internal.generic.ALOAD;
2784124Sdfrimport com.sun.org.apache.bcel.internal.generic.ASTORE;
2884124Sdfrimport com.sun.org.apache.bcel.internal.generic.BranchHandle;
2984124Sdfrimport com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
3084124Sdfrimport com.sun.org.apache.bcel.internal.generic.GOTO;
3184124Sdfrimport com.sun.org.apache.bcel.internal.generic.IFLT;
3284124Sdfrimport com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
3384124Sdfrimport com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
3484124Sdfrimport com.sun.org.apache.bcel.internal.generic.Instruction;
3584124Sdfrimport com.sun.org.apache.bcel.internal.generic.InstructionList;
3684124Sdfrimport com.sun.org.apache.bcel.internal.generic.PUSH;
3784124Sdfrimport com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
3884124Sdfrimport com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
3984124Sdfr
4084124Sdfr/**
4184124Sdfr * @author Jacek Ambroziak
4284124Sdfr * @author Santiago Pericas-Geertsen
4384124Sdfr */
4484124Sdfrpublic final class NodeSetType extends Type {
4584124Sdfr    protected NodeSetType() {}
4684124Sdfr
4784124Sdfr    public String toString() {
4884124Sdfr        return "node-set";
4984124Sdfr    }
5084124Sdfr
5184124Sdfr    public boolean identicalTo(Type other) {
5284124Sdfr        return this == other;
5384124Sdfr    }
5484124Sdfr
5584124Sdfr    public String toSignature() {
56119970Smarcel        return NODE_ITERATOR_SIG;
5784124Sdfr    }
58119970Smarcel
5984124Sdfr    public com.sun.org.apache.bcel.internal.generic.Type toJCType() {
60119970Smarcel        return new com.sun.org.apache.bcel.internal.generic.ObjectType(NODE_ITERATOR);
61119970Smarcel    }
6284124Sdfr
6384541Sdfr    /**
6484124Sdfr     * Translates a node-set into an object of internal type
6584124Sdfr     * <code>type</code>. The translation to int is undefined
6684124Sdfr     * since node-sets are always converted to
6784124Sdfr     * reals in arithmetic expressions.
6884124Sdfr     *
6984124Sdfr     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
7084124Sdfr     */
7184124Sdfr    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
7284124Sdfr                            Type type) {
7384124Sdfr        if (type == Type.String) {
7484124Sdfr            translateTo(classGen, methodGen, (StringType) type);
7584124Sdfr        }
7684124Sdfr        else if (type == Type.Boolean) {
7784124Sdfr            translateTo(classGen, methodGen, (BooleanType) type);
7884124Sdfr        }
7984124Sdfr        else if (type == Type.Real) {
8084124Sdfr            translateTo(classGen, methodGen, (RealType) type);
8184124Sdfr        }
8284124Sdfr        else if (type == Type.Node) {
8384124Sdfr            translateTo(classGen, methodGen, (NodeType) type);
8484124Sdfr        }
8584124Sdfr        else if (type == Type.Reference) {
8684124Sdfr            translateTo(classGen, methodGen, (ReferenceType) type);
8784124Sdfr        }
8884124Sdfr        else if (type == Type.Object) {
8984124Sdfr            translateTo(classGen, methodGen, (ObjectType) type);
9084124Sdfr        }
9184124Sdfr        else {
9284124Sdfr            ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
9384124Sdfr                                        toString(), type.toString());
9484124Sdfr            classGen.getParser().reportError(Constants.FATAL, err);
9584124Sdfr        }
9684124Sdfr    }
9784124Sdfr
9884124Sdfr    /**
99119970Smarcel     * Translates an external Java Class into an internal type.
100119970Smarcel     * Expects the Java object on the stack, pushes the internal type
10184124Sdfr     */
102119970Smarcel    public void translateFrom(ClassGenerator classGen,
103119970Smarcel        MethodGenerator methodGen, Class clazz)
10484124Sdfr    {
10584124Sdfr
10684124Sdfr        InstructionList il = methodGen.getInstructionList();
10784124Sdfr        ConstantPoolGen cpg = classGen.getConstantPool();
10884124Sdfr        if (clazz.getName().equals("org.w3c.dom.NodeList")) {
10984124Sdfr           // w3c NodeList is on the stack from the external Java function call.
11084124Sdfr           // call BasisFunction to consume NodeList and leave Iterator on
11184124Sdfr           //    the stack.
11284124Sdfr           il.append(classGen.loadTranslet());   // push translet onto stack
11384124Sdfr           il.append(methodGen.loadDOM());       // push DOM onto stack
11484124Sdfr           final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
11584124Sdfr                                        "nodeList2Iterator",
11684124Sdfr                                        "("
11784124Sdfr                                         + "Lorg/w3c/dom/NodeList;"
11884124Sdfr                                         + TRANSLET_INTF_SIG
11984124Sdfr                                         + DOM_INTF_SIG
12084124Sdfr                                         + ")" + NODE_ITERATOR_SIG );
12184124Sdfr           il.append(new INVOKESTATIC(convert));
12284124Sdfr        }
12384124Sdfr        else if (clazz.getName().equals("org.w3c.dom.Node")) {
12484124Sdfr           // w3c Node is on the stack from the external Java function call.
12584124Sdfr           // call BasisLibrary.node2Iterator() to consume Node and leave
12684124Sdfr           // Iterator on the stack.
12784124Sdfr           il.append(classGen.loadTranslet());   // push translet onto stack
128119970Smarcel           il.append(methodGen.loadDOM());       // push DOM onto stack
12984124Sdfr           final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
13084124Sdfr                                        "node2Iterator",
13184124Sdfr                                        "("
13284124Sdfr                                         + "Lorg/w3c/dom/Node;"
13384124Sdfr                                         + TRANSLET_INTF_SIG
13484124Sdfr                                         + DOM_INTF_SIG
13584124Sdfr                                         + ")" + NODE_ITERATOR_SIG );
13684124Sdfr           il.append(new INVOKESTATIC(convert));
13784124Sdfr        }
13884124Sdfr        else {
13984124Sdfr            ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
14084124Sdfr                toString(), clazz.getName());
14184124Sdfr            classGen.getParser().reportError(Constants.FATAL, err);
14284124Sdfr        }
14384124Sdfr    }
14484124Sdfr
14584124Sdfr
14684124Sdfr    /**
14784124Sdfr     * Translates a node-set into a synthesized boolean.
14884124Sdfr     * The boolean value of a node-set is "true" if non-empty
14984124Sdfr     * and "false" otherwise. Notice that the
15084124Sdfr     * function getFirstNode() is called in translateToDesynthesized().
15184124Sdfr     *
15284124Sdfr     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
15384124Sdfr     */
15484124Sdfr    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
15584124Sdfr                            BooleanType type) {
15684124Sdfr        final InstructionList il = methodGen.getInstructionList();
15784124Sdfr        FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
15884124Sdfr        il.append(ICONST_1);
15984124Sdfr        final BranchHandle truec = il.append(new GOTO(null));
16084124Sdfr        falsel.backPatch(il.append(ICONST_0));
16184124Sdfr        truec.setTarget(il.append(NOP));
16284124Sdfr    }
16384124Sdfr
16484124Sdfr    /**
16584124Sdfr     * Translates a node-set into a string. The string value of a node-set is
16684124Sdfr     * value of its first element.
16784124Sdfr     *
16884124Sdfr     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
16984124Sdfr     */
17084124Sdfr    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
17184124Sdfr                            StringType type) {
172100398Speter        final InstructionList il = methodGen.getInstructionList();
17384124Sdfr        getFirstNode(classGen, methodGen);
17484124Sdfr        il.append(DUP);
17584124Sdfr        final BranchHandle falsec = il.append(new IFLT(null));
17684124Sdfr        Type.Node.translateTo(classGen, methodGen, type);
17784124Sdfr        final BranchHandle truec = il.append(new GOTO(null));
17884124Sdfr        falsec.setTarget(il.append(POP));
17984124Sdfr        il.append(new PUSH(classGen.getConstantPool(), ""));
18084124Sdfr        truec.setTarget(il.append(NOP));
18184124Sdfr    }
18284124Sdfr
18384124Sdfr    /**
18484124Sdfr     * Expects a node-set on the stack and pushes a real.
18584124Sdfr     * First the node-set is converted to string, and from string to real.
18684124Sdfr     *
18784124Sdfr     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
18884124Sdfr     */
18984124Sdfr    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
19084124Sdfr                            RealType type) {
19184124Sdfr        translateTo(classGen, methodGen, Type.String);
19284124Sdfr        Type.String.translateTo(classGen, methodGen, Type.Real);
19384124Sdfr    }
19484124Sdfr
19584124Sdfr    /**
19684124Sdfr     * Expects a node-set on the stack and pushes a node.
19784124Sdfr     *
19884124Sdfr     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
19984124Sdfr     */
20084124Sdfr    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
20184124Sdfr                            NodeType type) {
20284124Sdfr        getFirstNode(classGen, methodGen);
20384124Sdfr    }
20484124Sdfr
20584124Sdfr    /**
20684124Sdfr     * Subsume node-set into ObjectType.
20784124Sdfr     *
20884124Sdfr     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
20984124Sdfr     */
21084124Sdfr    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
21184124Sdfr                            ObjectType type) {
21284124Sdfr            methodGen.getInstructionList().append(NOP);
21384124Sdfr    }
21484124Sdfr
21584124Sdfr    /**
21684124Sdfr     * Translates a node-set into a non-synthesized boolean. It does not
21784124Sdfr     * push a 0 or a 1 but instead returns branchhandle list to be appended
21884124Sdfr     * to the false list.
21984124Sdfr     *
22084541Sdfr     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized
22184541Sdfr     */
22284541Sdfr    public FlowList translateToDesynthesized(ClassGenerator classGen,
22384541Sdfr                                             MethodGenerator methodGen,
22484541Sdfr                                             BooleanType type) {
22584541Sdfr        final InstructionList il = methodGen.getInstructionList();
22684124Sdfr        getFirstNode(classGen, methodGen);
22784124Sdfr        return new FlowList(il.append(new IFLT(null)));
22884124Sdfr    }
22984124Sdfr
23084124Sdfr    /**
23184124Sdfr     * Expects a node-set on the stack and pushes a boxed node-set.
23284124Sdfr     * Node sets are already boxed so the translation is just a NOP.
23384124Sdfr     *
23484124Sdfr     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
23584124Sdfr     */
23684124Sdfr    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
23784124Sdfr                            ReferenceType type) {
23884124Sdfr        methodGen.getInstructionList().append(NOP);
23984124Sdfr    }
24084124Sdfr
24184124Sdfr    /**
24284124Sdfr     * Translates a node-set into the Java type denoted by <code>clazz</code>.
24384124Sdfr     * Expects a node-set on the stack and pushes an object of the appropriate
24484124Sdfr     * type after coercion.
24584124Sdfr     */
24684124Sdfr    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
24784124Sdfr                            Class clazz) {
24884124Sdfr        final ConstantPoolGen cpg = classGen.getConstantPool();
24984124Sdfr        final InstructionList il = methodGen.getInstructionList();
25084124Sdfr        final String className = clazz.getName();
25184124Sdfr
25284124Sdfr        il.append(methodGen.loadDOM());
25384124Sdfr        il.append(SWAP);
25484124Sdfr
25584124Sdfr        if (className.equals("org.w3c.dom.Node")) {
25684124Sdfr            int index = cpg.addInterfaceMethodref(DOM_INTF,
25784124Sdfr                                                  MAKE_NODE,
25884124Sdfr                                                  MAKE_NODE_SIG2);
25984124Sdfr            il.append(new INVOKEINTERFACE(index, 2));
26084124Sdfr        }
26184124Sdfr        else if (className.equals("org.w3c.dom.NodeList") ||
26284124Sdfr                 className.equals("java.lang.Object")) {
26384124Sdfr            int index = cpg.addInterfaceMethodref(DOM_INTF,
26484124Sdfr                                                  MAKE_NODE_LIST,
26584124Sdfr                                                  MAKE_NODE_LIST_SIG2);
26684124Sdfr            il.append(new INVOKEINTERFACE(index, 2));
26784124Sdfr        }
26884124Sdfr        else if (className.equals("java.lang.String")) {
26984124Sdfr            int next = cpg.addInterfaceMethodref(NODE_ITERATOR,
27084124Sdfr                                                 "next", "()I");
27184124Sdfr            int index = cpg.addInterfaceMethodref(DOM_INTF,
27284124Sdfr                                                 GET_NODE_VALUE,
27384124Sdfr                                                 "(I)"+STRING_SIG);
27484124Sdfr
27584124Sdfr            // Get next node from the iterator
27684124Sdfr            il.append(new INVOKEINTERFACE(next, 1));
27784124Sdfr            // Get the node's string value (from the DOM)
27884124Sdfr            il.append(new INVOKEINTERFACE(index, 2));
27984124Sdfr
28084124Sdfr        }
28184124Sdfr        else {
28284124Sdfr            ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
28384124Sdfr                                        toString(), className);
28484124Sdfr            classGen.getParser().reportError(Constants.FATAL, err);
28584124Sdfr        }
28684124Sdfr    }
28784124Sdfr
28884124Sdfr    /**
28984124Sdfr     * Some type conversions require gettting the first node from the node-set.
29084124Sdfr     * This function is defined to avoid code repetition.
29184124Sdfr     */
29284124Sdfr    private void getFirstNode(ClassGenerator classGen, MethodGenerator methodGen) {
29384124Sdfr        final ConstantPoolGen cpg = classGen.getConstantPool();
29484124Sdfr        final InstructionList il = methodGen.getInstructionList();
29584124Sdfr        il.append(new INVOKEINTERFACE(cpg.addInterfaceMethodref(NODE_ITERATOR,
29684124Sdfr                                                                NEXT,
29784124Sdfr                                                                NEXT_SIG), 1));
29884124Sdfr    }
29984124Sdfr
30084124Sdfr    /**
30184124Sdfr     * Translates an object of this type to its boxed representation.
30284124Sdfr     */
30384124Sdfr    public void translateBox(ClassGenerator classGen,
30484124Sdfr                             MethodGenerator methodGen) {
30584124Sdfr        translateTo(classGen, methodGen, Type.Reference);
30684124Sdfr    }
30784124Sdfr
30884124Sdfr    /**
30984124Sdfr     * Translates an object of this type to its unboxed representation.
31084124Sdfr     */
31184124Sdfr    public void translateUnBox(ClassGenerator classGen,
31284124Sdfr                               MethodGenerator methodGen) {
31384124Sdfr        methodGen.getInstructionList().append(NOP);
31484124Sdfr    }
31584124Sdfr
31684124Sdfr    /**
31784124Sdfr     * Returns the class name of an internal type's external representation.
31884124Sdfr     */
31984124Sdfr    public String getClassName() {
32084124Sdfr        return(NODE_ITERATOR);
32184124Sdfr    }
32284124Sdfr
32384124Sdfr
32484124Sdfr    public Instruction LOAD(int slot) {
32584124Sdfr        return new ALOAD(slot);
32684124Sdfr    }
32784124Sdfr
32884124Sdfr    public Instruction STORE(int slot) {
32984124Sdfr        return new ASTORE(slot);
33084124Sdfr    }
33184124Sdfr}
33284124Sdfr