KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > compiler > Number


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: Number.java,v 1.14 2004/02/24 02:58:42 zongaro Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import java.util.ArrayList JavaDoc;
23
24 import org.apache.bcel.classfile.Field;
25 import org.apache.bcel.generic.ALOAD;
26 import org.apache.bcel.generic.ASTORE;
27 import org.apache.bcel.generic.BranchHandle;
28 import org.apache.bcel.generic.CHECKCAST;
29 import org.apache.bcel.generic.ConstantPoolGen;
30 import org.apache.bcel.generic.GETFIELD;
31 import org.apache.bcel.generic.GOTO;
32 import org.apache.bcel.generic.IFNONNULL;
33 import org.apache.bcel.generic.INVOKESPECIAL;
34 import org.apache.bcel.generic.INVOKESTATIC;
35 import org.apache.bcel.generic.INVOKEVIRTUAL;
36 import org.apache.bcel.generic.InstructionList;
37 import org.apache.bcel.generic.L2I;
38 import org.apache.bcel.generic.LocalVariableGen;
39 import org.apache.bcel.generic.NEW;
40 import org.apache.bcel.generic.PUSH;
41 import org.apache.bcel.generic.PUTFIELD;
42 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
43 import org.apache.xalan.xsltc.compiler.util.MatchGenerator;
44 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
45 import org.apache.xalan.xsltc.compiler.util.NodeCounterGenerator;
46 import org.apache.xalan.xsltc.compiler.util.RealType;
47 import org.apache.xalan.xsltc.compiler.util.Type;
48 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
49 import org.apache.xalan.xsltc.compiler.util.Util;
50
51 /**
52  * @author Jacek Ambroziak
53  * @author Santiago Pericas-Geertsen
54  */

55 final class Number extends Instruction implements Closure {
56     private static final int LEVEL_SINGLE = 0;
57     private static final int LEVEL_MULTIPLE = 1;
58     private static final int LEVEL_ANY = 2;
59
60     static final private String JavaDoc[] ClassNames = {
61     "org.apache.xalan.xsltc.dom.SingleNodeCounter", // LEVEL_SINGLE
62
"org.apache.xalan.xsltc.dom.MultipleNodeCounter", // LEVEL_MULTIPLE
63
"org.apache.xalan.xsltc.dom.AnyNodeCounter" // LEVEL_ANY
64
};
65
66     static final private String JavaDoc[] FieldNames = {
67     "___single_node_counter", // LEVEL_SINGLE
68
"___multiple_node_counter", // LEVEL_MULTIPLE
69
"___any_node_counter" // LEVEL_ANY
70
};
71
72     private Pattern _from = null;
73     private Pattern _count = null;
74     private Expression _value = null;
75
76     private AttributeValueTemplate _lang = null;
77     private AttributeValueTemplate _format = null;
78     private AttributeValueTemplate _letterValue = null;
79     private AttributeValueTemplate _groupingSeparator = null;
80     private AttributeValueTemplate _groupingSize = null;
81
82     private int _level = LEVEL_SINGLE;
83     private boolean _formatNeeded = false;
84
85     private String JavaDoc _className = null;
86     private ArrayList JavaDoc _closureVars = null;
87
88      // -- Begin Closure interface --------------------
89

90     /**
91      * Returns true if this closure is compiled in an inner class (i.e.
92      * if this is a real closure).
93      */

94     public boolean inInnerClass() {
95     return (_className != null);
96     }
97
98     /**
99      * Returns a reference to its parent closure or null if outermost.
100      */

101     public Closure getParentClosure() {
102     return null;
103     }
104
105     /**
106      * Returns the name of the auxiliary class or null if this predicate
107      * is compiled inside the Translet.
108      */

109     public String JavaDoc getInnerClassName() {
110     return _className;
111     }
112
113     /**
114      * Add new variable to the closure.
115      */

116     public void addVariable(VariableRefBase variableRef) {
117     if (_closureVars == null) {
118         _closureVars = new ArrayList JavaDoc();
119     }
120
121     // Only one reference per variable
122
if (!_closureVars.contains(variableRef)) {
123         _closureVars.add(variableRef);
124     }
125     }
126
127     // -- End Closure interface ----------------------
128

129    public void parseContents(Parser parser) {
130     final int count = _attributes.getLength();
131
132     for (int i = 0; i < count; i++) {
133         final String JavaDoc name = _attributes.getQName(i);
134         final String JavaDoc value = _attributes.getValue(i);
135
136         if (name.equals("value")) {
137         _value = parser.parseExpression(this, name, null);
138         }
139         else if (name.equals("count")) {
140         _count = parser.parsePattern(this, name, null);
141         }
142         else if (name.equals("from")) {
143         _from = parser.parsePattern(this, name, null);
144         }
145         else if (name.equals("level")) {
146         if (value.equals("single")) {
147             _level = LEVEL_SINGLE;
148         }
149         else if (value.equals("multiple")) {
150             _level = LEVEL_MULTIPLE;
151         }
152         else if (value.equals("any")) {
153             _level = LEVEL_ANY;
154         }
155         }
156         else if (name.equals("format")) {
157         _format = new AttributeValueTemplate(value, parser, this);
158         _formatNeeded = true;
159         }
160         else if (name.equals("lang")) {
161         _lang = new AttributeValueTemplate(value, parser, this);
162         _formatNeeded = true;
163         }
164         else if (name.equals("letter-value")) {
165         _letterValue = new AttributeValueTemplate(value, parser, this);
166         _formatNeeded = true;
167         }
168         else if (name.equals("grouping-separator")) {
169         _groupingSeparator = new AttributeValueTemplate(value, parser, this);
170         _formatNeeded = true;
171         }
172         else if (name.equals("grouping-size")) {
173         _groupingSize = new AttributeValueTemplate(value, parser, this);
174         _formatNeeded = true;
175         }
176     }
177     }
178
179     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
180     if (_value != null) {
181         Type tvalue = _value.typeCheck(stable);
182         if (tvalue instanceof RealType == false) {
183         _value = new CastExpr(_value, Type.Real);
184         }
185     }
186     if (_count != null) {
187         _count.typeCheck(stable);
188     }
189     if (_from != null) {
190         _from.typeCheck(stable);
191     }
192     if (_format != null) {
193         _format.typeCheck(stable);
194     }
195     if (_lang != null) {
196         _lang.typeCheck(stable);
197     }
198     if (_letterValue != null) {
199         _letterValue.typeCheck(stable);
200     }
201     if (_groupingSeparator != null) {
202         _groupingSeparator.typeCheck(stable);
203     }
204     if (_groupingSize != null) {
205         _groupingSize.typeCheck(stable);
206     }
207     return Type.Void;
208     }
209
210     /**
211      * True if the has specified a value for this instance of number.
212      */

213     public boolean hasValue() {
214     return _value != null;
215     }
216
217     /**
218      * Returns <tt>true</tt> if this instance of number has neither
219      * a from nor a count pattern.
220      */

221     public boolean isDefault() {
222     return _from == null && _count == null;
223     }
224
225     private void compileDefault(ClassGenerator classGen,
226                     MethodGenerator methodGen) {
227     int index;
228     ConstantPoolGen cpg = classGen.getConstantPool();
229     InstructionList il = methodGen.getInstructionList();
230
231     int[] fieldIndexes = getXSLTC().getNumberFieldIndexes();
232
233     if (fieldIndexes[_level] == -1) {
234         Field defaultNode = new Field(ACC_PRIVATE,
235                       cpg.addUtf8(FieldNames[_level]),
236                       cpg.addUtf8(NODE_COUNTER_SIG),
237                       null,
238                       cpg.getConstantPool());
239
240         // Add a new private field to this class
241
classGen.addField(defaultNode);
242
243         // Get a reference to the newly added field
244
fieldIndexes[_level] = cpg.addFieldref(classGen.getClassName(),
245                            FieldNames[_level],
246                            NODE_COUNTER_SIG);
247     }
248
249     // Check if field is initialized (runtime)
250
il.append(classGen.loadTranslet());
251     il.append(new GETFIELD(fieldIndexes[_level]));
252     final BranchHandle ifBlock1 = il.append(new IFNONNULL(null));
253
254     // Create an instance of DefaultNodeCounter
255
index = cpg.addMethodref(ClassNames[_level],
256                  "getDefaultNodeCounter",
257                  "(" + TRANSLET_INTF_SIG
258                  + DOM_INTF_SIG
259                  + NODE_ITERATOR_SIG
260                  + ")" + NODE_COUNTER_SIG);
261     il.append(classGen.loadTranslet());
262     il.append(methodGen.loadDOM());
263     il.append(methodGen.loadIterator());
264     il.append(new INVOKESTATIC(index));
265     il.append(DUP);
266
267     // Store the node counter in the field
268
il.append(classGen.loadTranslet());
269     il.append(SWAP);
270     il.append(new PUTFIELD(fieldIndexes[_level]));
271     final BranchHandle ifBlock2 = il.append(new GOTO(null));
272
273     // Backpatch conditionals
274
ifBlock1.setTarget(il.append(classGen.loadTranslet()));
275     il.append(new GETFIELD(fieldIndexes[_level]));
276     
277     ifBlock2.setTarget(il.append(NOP));
278     }
279
280     /**
281      * Compiles a constructor for the class <tt>_className</tt> that
282      * inherits from {Any,Single,Multiple}NodeCounter. This constructor
283      * simply calls the same constructor in the super class.
284      */

285     private void compileConstructor(ClassGenerator classGen) {
286     MethodGenerator cons;
287     final InstructionList il = new InstructionList();
288     final ConstantPoolGen cpg = classGen.getConstantPool();
289
290     cons = new MethodGenerator(ACC_PUBLIC,
291                    org.apache.bcel.generic.Type.VOID,
292                    new org.apache.bcel.generic.Type[] {
293                        Util.getJCRefType(TRANSLET_INTF_SIG),
294                        Util.getJCRefType(DOM_INTF_SIG),
295                        Util.getJCRefType(NODE_ITERATOR_SIG)
296                    },
297                    new String JavaDoc[] {
298                        "dom",
299                        "translet",
300                        "iterator"
301                    },
302                    "<init>", _className, il, cpg);
303
304     il.append(ALOAD_0); // this
305
il.append(ALOAD_1); // translet
306
il.append(ALOAD_2); // DOM
307
il.append(new ALOAD(3));// iterator
308

309     int index = cpg.addMethodref(ClassNames[_level],
310                      "<init>",
311                      "(" + TRANSLET_INTF_SIG
312                      + DOM_INTF_SIG
313                      + NODE_ITERATOR_SIG
314                      + ")V");
315     il.append(new INVOKESPECIAL(index));
316     il.append(RETURN);
317     
318     cons.stripAttributes(true);
319     cons.setMaxLocals();
320     cons.setMaxStack();
321     classGen.addMethod(cons.getMethod());
322     }
323
324     /**
325      * This method compiles code that is common to matchesFrom() and
326      * matchesCount() in the auxillary class.
327      */

328     private void compileLocals(NodeCounterGenerator nodeCounterGen,
329                    MatchGenerator matchGen,
330                    InstructionList il)
331     {
332     int field;
333     LocalVariableGen local;
334     ConstantPoolGen cpg = nodeCounterGen.getConstantPool();
335
336     // Get NodeCounter._iterator and store locally
337
local = matchGen.addLocalVariable("iterator",
338                       Util.getJCRefType(NODE_ITERATOR_SIG),
339                       null, null);
340     field = cpg.addFieldref(NODE_COUNTER, "_iterator",
341                 ITERATOR_FIELD_SIG);
342     il.append(ALOAD_0); // 'this' pointer on stack
343
il.append(new GETFIELD(field));
344     il.append(new ASTORE(local.getIndex()));
345     matchGen.setIteratorIndex(local.getIndex());
346     
347     // Get NodeCounter._translet and store locally
348
local = matchGen.addLocalVariable("translet",
349                   Util.getJCRefType(TRANSLET_SIG),
350                   null, null);
351     field = cpg.addFieldref(NODE_COUNTER, "_translet",
352                 "Lorg/apache/xalan/xsltc/Translet;");
353     il.append(ALOAD_0); // 'this' pointer on stack
354
il.append(new GETFIELD(field));
355     il.append(new CHECKCAST(cpg.addClass(TRANSLET_CLASS)));
356     il.append(new ASTORE(local.getIndex()));
357     nodeCounterGen.setTransletIndex(local.getIndex());
358
359     // Get NodeCounter._document and store locally
360
local = matchGen.addLocalVariable("document",
361                       Util.getJCRefType(DOM_INTF_SIG),
362                       null, null);
363     field = cpg.addFieldref(_className, "_document", DOM_INTF_SIG);
364     il.append(ALOAD_0); // 'this' pointer on stack
365
il.append(new GETFIELD(field));
366     // Make sure we have the correct DOM type on the stack!!!
367
il.append(new ASTORE(local.getIndex()));
368     matchGen.setDomIndex(local.getIndex());
369     }
370
371     private void compilePatterns(ClassGenerator classGen,
372                  MethodGenerator methodGen)
373     {
374     int current;
375     int field;
376     LocalVariableGen local;
377     MatchGenerator matchGen;
378     NodeCounterGenerator nodeCounterGen;
379
380     _className = getXSLTC().getHelperClassName();
381     nodeCounterGen = new NodeCounterGenerator(_className,
382                           ClassNames[_level],
383                           toString(),
384                           ACC_PUBLIC | ACC_SUPER,
385                           null,
386                           classGen.getStylesheet());
387     InstructionList il = null;
388     ConstantPoolGen cpg = nodeCounterGen.getConstantPool();
389
390     // Add a new instance variable for each var in closure
391
final int closureLen = (_closureVars == null) ? 0 :
392         _closureVars.size();
393
394     for (int i = 0; i < closureLen; i++) {
395         VariableBase var =
396         ((VariableRefBase) _closureVars.get(i)).getVariable();
397
398         nodeCounterGen.addField(new Field(ACC_PUBLIC,
399                     cpg.addUtf8(var.getEscapedName()),
400                     cpg.addUtf8(var.getType().toSignature()),
401                     null, cpg.getConstantPool()));
402     }
403
404     // Add a single constructor to the class
405
compileConstructor(nodeCounterGen);
406
407     /*
408      * Compile method matchesFrom()
409      */

410     if (_from != null) {
411         il = new InstructionList();
412         matchGen =
413         new MatchGenerator(ACC_PUBLIC | ACC_FINAL,
414                    org.apache.bcel.generic.Type.BOOLEAN,
415                    new org.apache.bcel.generic.Type[] {
416                        org.apache.bcel.generic.Type.INT,
417                    },
418                    new String JavaDoc[] {
419                        "node",
420                    },
421                    "matchesFrom", _className, il, cpg);
422
423         compileLocals(nodeCounterGen,matchGen,il);
424
425         // Translate Pattern
426
il.append(matchGen.loadContextNode());
427         _from.translate(nodeCounterGen, matchGen);
428         _from.synthesize(nodeCounterGen, matchGen);
429         il.append(IRETURN);
430             
431         matchGen.stripAttributes(true);
432         matchGen.setMaxLocals();
433         matchGen.setMaxStack();
434         matchGen.removeNOPs();
435         nodeCounterGen.addMethod(matchGen.getMethod());
436     }
437
438     /*
439      * Compile method matchesCount()
440      */

441     if (_count != null) {
442         il = new InstructionList();
443         matchGen = new MatchGenerator(ACC_PUBLIC | ACC_FINAL,
444                       org.apache.bcel.generic.Type.BOOLEAN,
445                       new org.apache.bcel.generic.Type[] {
446                           org.apache.bcel.generic.Type.INT,
447                       },
448                       new String JavaDoc[] {
449                           "node",
450                       },
451                       "matchesCount", _className, il, cpg);
452
453         compileLocals(nodeCounterGen,matchGen,il);
454         
455         // Translate Pattern
456
il.append(matchGen.loadContextNode());
457         _count.translate(nodeCounterGen, matchGen);
458         _count.synthesize(nodeCounterGen, matchGen);
459         
460         il.append(IRETURN);
461             
462         matchGen.stripAttributes(true);
463         matchGen.setMaxLocals();
464         matchGen.setMaxStack();
465         matchGen.removeNOPs();
466         nodeCounterGen.addMethod(matchGen.getMethod());
467     }
468     
469     getXSLTC().dumpClass(nodeCounterGen.getJavaClass());
470
471     // Push an instance of the newly created class
472
cpg = classGen.getConstantPool();
473     il = methodGen.getInstructionList();
474
475     final int index = cpg.addMethodref(_className, "<init>",
476                        "(" + TRANSLET_INTF_SIG
477                        + DOM_INTF_SIG
478                        + NODE_ITERATOR_SIG
479                        + ")V");
480     il.append(new NEW(cpg.addClass(_className)));
481     il.append(DUP);
482     il.append(classGen.loadTranslet());
483     il.append(methodGen.loadDOM());
484     il.append(methodGen.loadIterator());
485     il.append(new INVOKESPECIAL(index));
486
487     // Initialize closure variables
488
for (int i = 0; i < closureLen; i++) {
489         final VariableRefBase varRef = (VariableRefBase) _closureVars.get(i);
490         final VariableBase var = varRef.getVariable();
491         final Type varType = var.getType();
492
493         // Store variable in new closure
494
il.append(DUP);
495         il.append(var.loadInstruction());
496         il.append(new PUTFIELD(
497             cpg.addFieldref(_className, var.getEscapedName(),
498             varType.toSignature())));
499     }
500     }
501
502     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
503     int index;
504     final ConstantPoolGen cpg = classGen.getConstantPool();
505     final InstructionList il = methodGen.getInstructionList();
506
507     // Push "this" for the call to characters()
508
il.append(classGen.loadTranslet());
509
510     if (hasValue()) {
511         compileDefault(classGen, methodGen);
512         _value.translate(classGen, methodGen);
513
514         // Round the number to the nearest integer
515
index = cpg.addMethodref(MATH_CLASS, "round", "(D)J");
516         il.append(new INVOKESTATIC(index));
517         il.append(new L2I());
518
519         // Call setValue on the node counter
520
index = cpg.addMethodref(NODE_COUNTER,
521                      "setValue",
522                      "(I)" + NODE_COUNTER_SIG);
523         il.append(new INVOKEVIRTUAL(index));
524     }
525     else if (isDefault()) {
526         compileDefault(classGen, methodGen);
527     }
528     else {
529         compilePatterns(classGen, methodGen);
530     }
531
532     // Call setStartNode()
533
if (!hasValue()) {
534         il.append(methodGen.loadContextNode());
535         index = cpg.addMethodref(NODE_COUNTER,
536                      SET_START_NODE,
537                      "(I)" + NODE_COUNTER_SIG);
538         il.append(new INVOKEVIRTUAL(index));
539     }
540
541     // Call getCounter() with or without args
542
if (_formatNeeded) {
543         if (_format != null) {
544         _format.translate(classGen, methodGen);
545         }
546         else {
547         il.append(new PUSH(cpg, "1"));
548         }
549
550         if (_lang != null) {
551         _lang.translate(classGen, methodGen);
552         }
553         else {
554         il.append(new PUSH(cpg, "en")); // TODO ??
555
}
556
557         if (_letterValue != null) {
558         _letterValue.translate(classGen, methodGen);
559         }
560         else {
561         il.append(new PUSH(cpg, Constants.EMPTYSTRING));
562         }
563
564         if (_groupingSeparator != null) {
565         _groupingSeparator.translate(classGen, methodGen);
566         }
567         else {
568         il.append(new PUSH(cpg, Constants.EMPTYSTRING));
569         }
570
571         if (_groupingSize != null) {
572         _groupingSize.translate(classGen, methodGen);
573         }
574         else {
575         il.append(new PUSH(cpg, "0"));
576         }
577
578         index = cpg.addMethodref(NODE_COUNTER, "getCounter",
579                      "(" + STRING_SIG + STRING_SIG
580                      + STRING_SIG + STRING_SIG
581                      + STRING_SIG + ")" + STRING_SIG);
582         il.append(new INVOKEVIRTUAL(index));
583     }
584     else {
585         index = cpg.addMethodref(NODE_COUNTER, "setDefaultFormatting",
586                      "()" + NODE_COUNTER_SIG);
587         il.append(new INVOKEVIRTUAL(index));
588
589         index = cpg.addMethodref(NODE_COUNTER, "getCounter",
590                      "()" + STRING_SIG);
591         il.append(new INVOKEVIRTUAL(index));
592     }
593
594     // Output the resulting string to the handler
595
il.append(methodGen.loadHandler());
596     index = cpg.addMethodref(TRANSLET_CLASS,
597                  CHARACTERSW,
598                  CHARACTERSW_SIG);
599     il.append(new INVOKEVIRTUAL(index));
600     }
601 }
602
Popular Tags