Source Code Cross Referenced for NFSubstitution.java in  » Internationalization-Localization » icu4j » com » ibm » icu » text » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Internationalization Localization » icu4j » com.ibm.icu.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *******************************************************************************
0003:         * Copyright (C) 1996-2004, International Business Machines Corporation and    *
0004:         * others. All Rights Reserved.                                                *
0005:         *******************************************************************************
0006:         */
0007:        package com.ibm.icu.text;
0008:
0009:        import java.text.*;
0010:
0011:        //===================================================================
0012:        // NFSubstitution (abstract base class)
0013:        //===================================================================
0014:
0015:        /**
0016:         * An abstract class defining protocol for substitutions.  A substitution
0017:         * is a section of a rule that inserts text into the rule's rule text
0018:         * based on some part of the number being formatted.
0019:         * @author Richard Gillam
0020:         */
0021:        abstract class NFSubstitution {
0022:            //-----------------------------------------------------------------------
0023:            // constants
0024:            //-----------------------------------------------------------------------
0025:
0026:            /**
0027:             * Puts a copyright in the .class file
0028:             */
0029:            private static final String copyrightNotice = "Copyright \u00a91997-2004 IBM Corp.  All rights reserved.";
0030:
0031:            //-----------------------------------------------------------------------
0032:            // data members
0033:            //-----------------------------------------------------------------------
0034:
0035:            /**
0036:             * The substitution's position in the rule text of the rule that owns it
0037:             */
0038:            int pos;
0039:
0040:            /**
0041:             * The rule set this substitution uses to format its result, or null.
0042:             * (Either this or numberFormat has to be non-null.)
0043:             */
0044:            NFRuleSet ruleSet = null;
0045:
0046:            /**
0047:             * The DecimalFormat this substitution uses to format its result,
0048:             * or null.  (Either this or ruleSet has to be non-null.)
0049:             */
0050:            DecimalFormat numberFormat = null;
0051:
0052:            //-----------------------------------------------------------------------
0053:            // construction
0054:            //-----------------------------------------------------------------------
0055:
0056:            /**
0057:             * Parses the description, creates the right kind of substitution,
0058:             * and initializes it based on the description.
0059:             * @param pos The substitution's position in the rule text of the
0060:             * rule that owns it.
0061:             * @param rule The rule containing this substitution
0062:             * @param rulePredecessor The rule preceding the one that contains
0063:             * this substitution in the rule set's rule list (this is used
0064:             * only for >>> substitutions).
0065:             * @param ruleSet The rule set containing the rule containing this
0066:             * substitution
0067:             * @param formatter The RuleBasedNumberFormat that ultimately owns
0068:             * this substitution
0069:             * @param description The description to parse to build the substitution
0070:             * (this is just the substring of the rule's description containing
0071:             * the substitution token itself)
0072:             * @return A new substitution constructed according to the description
0073:             */
0074:            public static NFSubstitution makeSubstitution(int pos, NFRule rule,
0075:                    NFRule rulePredecessor, NFRuleSet ruleSet,
0076:                    RuleBasedNumberFormat formatter, String description) {
0077:                // if the description is empty, return a NummSubstitution
0078:                if (description.length() == 0) {
0079:                    return new NullSubstitution(pos, ruleSet, formatter,
0080:                            description);
0081:                }
0082:
0083:                switch (description.charAt(0)) {
0084:                // if the description begins with '<'...
0085:                case '<':
0086:                    // throw an exception if the rule is a negative number
0087:                    // rule
0088:                    if (rule.getBaseValue() == NFRule.NEGATIVE_NUMBER_RULE) {
0089:                        throw new IllegalArgumentException(
0090:                                "<< not allowed in negative-number rule");
0091:                    }
0092:
0093:                    // if the rule is a fraction rule, return an
0094:                    // IntegralPartSubstitution
0095:                    else if (rule.getBaseValue() == NFRule.IMPROPER_FRACTION_RULE
0096:                            || rule.getBaseValue() == NFRule.PROPER_FRACTION_RULE
0097:                            || rule.getBaseValue() == NFRule.MASTER_RULE) {
0098:                        return new IntegralPartSubstitution(pos, ruleSet,
0099:                                formatter, description);
0100:                    }
0101:
0102:                    // if the rule set containing the rule is a fraction
0103:                    // rule set, return a NumeratorSubstitution
0104:                    else if (ruleSet.isFractionSet()) {
0105:                        return new NumeratorSubstitution(pos, rule
0106:                                .getBaseValue(), formatter.getDefaultRuleSet(),
0107:                                formatter, description);
0108:                    }
0109:
0110:                    // otherwise, return a MultiplierSubstitution
0111:                    else {
0112:                        return new MultiplierSubstitution(pos, rule
0113:                                .getDivisor(), ruleSet, formatter, description);
0114:                    }
0115:
0116:                    // if the description begins with '>'...
0117:                case '>':
0118:                    // if the rule is a negative-number rule, return
0119:                    // an AbsoluteValueSubstitution
0120:                    if (rule.getBaseValue() == NFRule.NEGATIVE_NUMBER_RULE) {
0121:                        return new AbsoluteValueSubstitution(pos, ruleSet,
0122:                                formatter, description);
0123:                    }
0124:
0125:                    // if the rule is a fraction rule, return a
0126:                    // FractionalPartSubstitution
0127:                    else if (rule.getBaseValue() == NFRule.IMPROPER_FRACTION_RULE
0128:                            || rule.getBaseValue() == NFRule.PROPER_FRACTION_RULE
0129:                            || rule.getBaseValue() == NFRule.MASTER_RULE) {
0130:                        return new FractionalPartSubstitution(pos, ruleSet,
0131:                                formatter, description);
0132:                    }
0133:
0134:                    // if the rule set owning the rule is a fraction rule set,
0135:                    // throw an exception
0136:                    else if (ruleSet.isFractionSet()) {
0137:                        throw new IllegalArgumentException(
0138:                                ">> not allowed in fraction rule set");
0139:                    }
0140:
0141:                    // otherwise, return a ModulusSubstitution
0142:                    else {
0143:                        return new ModulusSubstitution(pos, rule.getDivisor(),
0144:                                rulePredecessor, ruleSet, formatter,
0145:                                description);
0146:                    }
0147:
0148:                    // if the description begins with '=', always return a
0149:                    // SameValueSubstitution
0150:                case '=':
0151:                    return new SameValueSubstitution(pos, ruleSet, formatter,
0152:                            description);
0153:
0154:                    // and if it's anything else, throw an exception
0155:                default:
0156:                    throw new IllegalArgumentException(
0157:                            "Illegal substitution character");
0158:                }
0159:            }
0160:
0161:            /**
0162:             * Base constructor for substitutions.  This constructor sets up the
0163:             * fields which are common to all substitutions.
0164:             * @param pos The substitution's position in the owning rule's rule
0165:             * text
0166:             * @param ruleSet The rule set that owns this substitution
0167:             * @param formatter The RuleBasedNumberFormat that owns this substitution
0168:             * @param description The substitution descriptor (i.e., the text
0169:             * inside the token characters)
0170:             */
0171:            NFSubstitution(int pos, NFRuleSet ruleSet,
0172:                    RuleBasedNumberFormat formatter, String description) {
0173:                // initialize the substitution's position in its parent rule
0174:                this .pos = pos;
0175:
0176:                // the description should begin and end with the same character.
0177:                // If it doesn't that's a syntax error.  Otherwise,
0178:                // makeSubstitution() was the only thing that needed to know
0179:                // about these characters, so strip them off
0180:                if (description.length() >= 2
0181:                        && description.charAt(0) == description
0182:                                .charAt(description.length() - 1)) {
0183:                    description = description.substring(1,
0184:                            description.length() - 1);
0185:                } else if (description.length() != 0) {
0186:                    throw new IllegalArgumentException(
0187:                            "Illegal substitution syntax");
0188:                }
0189:
0190:                // if the description was just two paired token characters
0191:                // (i.e., "<<" or ">>"), it uses the rule set it belongs to to
0192:                // format its result
0193:                if (description.length() == 0) {
0194:                    this .ruleSet = ruleSet;
0195:                }
0196:
0197:                // if the description contains a rule set name, that's the rule
0198:                // set we use to format the result: get a reference to the
0199:                // names rule set
0200:                else if (description.charAt(0) == '%') {
0201:                    this .ruleSet = formatter.findRuleSet(description);
0202:                }
0203:
0204:                // if the description begins with 0 or #, treat it as a
0205:                // DecimalFormat pattern, and initialize a DecimalFormat with
0206:                // that pattern (then set it to use the DecimalFormatSymbols
0207:                // belonging to our formatter)
0208:                else if (description.charAt(0) == '#'
0209:                        || description.charAt(0) == '0') {
0210:                    this .numberFormat = new DecimalFormat(description);
0211:                    this .numberFormat.setDecimalFormatSymbols(formatter
0212:                            .getDecimalFormatSymbols());
0213:                }
0214:
0215:                // if the description is ">>>", this substitution bypasses the
0216:                // usual rule-search process and always uses the rule that precedes
0217:                // it in its own rule set's rule list (this is used for place-value
0218:                // notations: formats where you want to see a particular part of
0219:                // a number even when it's 0)
0220:                else if (description.charAt(0) == '>') {
0221:                    this .ruleSet = ruleSet; // was null, thai rules added to control space
0222:                    this .numberFormat = null;
0223:                }
0224:
0225:                // and of the description is none of these things, it's a syntax error
0226:                else {
0227:                    throw new IllegalArgumentException(
0228:                            "Illegal substitution syntax");
0229:                }
0230:            }
0231:
0232:            /**
0233:             * Set's the substitution's divisor.  Used by NFRule.setBaseValue().
0234:             * A no-op for all substitutions except multiplier and modulus
0235:             * substitutions.
0236:             * @param radix The radix of the divisor
0237:             * @param exponent The exponent of the divisor
0238:             */
0239:            public void setDivisor(int radix, int exponent) {
0240:                // a no-op for all substitutions except multiplier and modulus substitutions
0241:            }
0242:
0243:            //-----------------------------------------------------------------------
0244:            // boilerplate
0245:            //-----------------------------------------------------------------------
0246:
0247:            /**
0248:             * Compares two substitutions for equality
0249:             * @param The substitution to compare this one to
0250:             * @return true if the two substitutions are functionally equivalent
0251:             */
0252:            public boolean equals(Object that) {
0253:                // compare class and all of the fields all substitutions have
0254:                // in common
0255:                if (this .getClass() == that.getClass()) {
0256:                    NFSubstitution that2 = (NFSubstitution) that;
0257:
0258:                    return pos == that2.pos
0259:                            && (ruleSet == null ? that2.ruleSet == null : true) // can't compare tree structure, no .equals or recurse
0260:                            && (numberFormat == null ? (that2.numberFormat == null)
0261:                                    : numberFormat.equals(that2.numberFormat));
0262:                }
0263:                return false;
0264:            }
0265:
0266:            /**
0267:             * Returns a textual description of the substitution
0268:             * @return A textual description of the substitution.  This might
0269:             * not be identical to the description it was created from, but
0270:             * it'll produce the same result.
0271:             */
0272:            public String toString() {
0273:                // use tokenChar() to get the character at the beginning and
0274:                // end of the substitution token.  In between them will go
0275:                // either the name of the rule set it uses, or the pattern of
0276:                // the DecimalFormat it uses
0277:                if (ruleSet != null) {
0278:                    return tokenChar() + ruleSet.getName() + tokenChar();
0279:                } else {
0280:                    return tokenChar() + numberFormat.toPattern() + tokenChar();
0281:                }
0282:            }
0283:
0284:            //-----------------------------------------------------------------------
0285:            // formatting
0286:            //-----------------------------------------------------------------------
0287:
0288:            /**
0289:             * Performs a mathematical operation on the number, formats it using
0290:             * either ruleSet or decimalFormat, and inserts the result into
0291:             * toInsertInto.
0292:             * @param number The number being formatted.
0293:             * @param toInsertInto The string we insert the result into
0294:             * @param pos The position in toInsertInto where the owning rule's
0295:             * rule text begins (this value is added to this substitution's
0296:             * position to determine exactly where to insert the new text)
0297:             */
0298:            public void doSubstitution(long number, StringBuffer toInsertInto,
0299:                    int pos) {
0300:                if (ruleSet != null) {
0301:                    // perform a transformation on the number that is dependent
0302:                    // on the type of substitution this is, then just call its
0303:                    // rule set's format() method to format the result
0304:                    long numberToFormat = transformNumber(number);
0305:
0306:                    ruleSet
0307:                            .format(numberToFormat, toInsertInto, pos
0308:                                    + this .pos);
0309:                } else {
0310:                    // or perform the transformation on the number (preserving
0311:                    // the result's fractional part if the formatter it set
0312:                    // to show it), then use that formatter's format() method
0313:                    // to format the result
0314:                    double numberToFormat = transformNumber((double) number);
0315:                    if (numberFormat.getMaximumFractionDigits() == 0) {
0316:                        numberToFormat = Math.floor(numberToFormat);
0317:                    }
0318:
0319:                    toInsertInto.insert(pos + this .pos, numberFormat
0320:                            .format(numberToFormat));
0321:                }
0322:            }
0323:
0324:            /**
0325:             * Performs a mathematical operation on the number, formats it using
0326:             * either ruleSet or decimalFormat, and inserts the result into
0327:             * toInsertInto.
0328:             * @param number The number being formatted.
0329:             * @param toInsertInto The string we insert the result into
0330:             * @param pos The position in toInsertInto where the owning rule's
0331:             * rule text begins (this value is added to this substitution's
0332:             * position to determine exactly where to insert the new text)
0333:             */
0334:            public void doSubstitution(double number,
0335:                    StringBuffer toInsertInto, int pos) {
0336:                // perform a transformation on the number being formatted that
0337:                // is dependent on the type of substitution this is
0338:                double numberToFormat = transformNumber(number);
0339:
0340:                // if the result is an integer, from here on out we work in integer
0341:                // space (saving time and memory and preserving accuracy)
0342:                if (numberToFormat == Math.floor(numberToFormat)
0343:                        && ruleSet != null) {
0344:                    ruleSet.format((long) numberToFormat, toInsertInto, pos
0345:                            + this .pos);
0346:
0347:                    // if the result isn't an integer, then call either our rule set's
0348:                    // format() method or our DecimalFormat's format() method to
0349:                    // format the result
0350:                } else {
0351:                    if (ruleSet != null) {
0352:                        ruleSet.format(numberToFormat, toInsertInto, pos
0353:                                + this .pos);
0354:                    } else {
0355:                        toInsertInto.insert(pos + this .pos, numberFormat
0356:                                .format(numberToFormat));
0357:                    }
0358:                }
0359:            }
0360:
0361:            /**
0362:             * Subclasses override this function to perform some kind of
0363:             * mathematical operation on the number.  The result of this operation
0364:             * is formatted using the rule set or DecimalFormat that this
0365:             * substitution refers to, and the result is inserted into the result
0366:             * string.
0367:             * @param The number being formatted
0368:             * @return The result of performing the opreration on the number
0369:             */
0370:            public abstract long transformNumber(long number);
0371:
0372:            /**
0373:             * Subclasses override this function to perform some kind of
0374:             * mathematical operation on the number.  The result of this operation
0375:             * is formatted using the rule set or DecimalFormat that this
0376:             * substitution refers to, and the result is inserted into the result
0377:             * string.
0378:             * @param The number being formatted
0379:             * @return The result of performing the opreration on the number
0380:             */
0381:            public abstract double transformNumber(double number);
0382:
0383:            //-----------------------------------------------------------------------
0384:            // parsing
0385:            //-----------------------------------------------------------------------
0386:
0387:            /**
0388:             * Parses a string using the rule set or DecimalFormat belonging
0389:             * to this substitution.  If there's a match, a mathematical
0390:             * operation (the inverse of the one used in formatting) is
0391:             * performed on the result of the parse and the value passed in
0392:             * and returned as the result.  The parse position is updated to
0393:             * point to the first unmatched character in the string.
0394:             * @param text The string to parse
0395:             * @param parsePosition On entry, ignored, but assumed to be 0.
0396:             * On exit, this is updated to point to the first unmatched
0397:             * character (or 0 if the substitution didn't match)
0398:             * @param baseValue A partial parse result that should be
0399:             * combined with the result of this parse
0400:             * @param upperBound When searching the rule set for a rule
0401:             * matching the string passed in, only rules with base values
0402:             * lower than this are considered
0403:             * @param lenientParse If true and matching against rules fails,
0404:             * the substitution will also try matching the text against
0405:             * numerals using a default-costructed NumberFormat.  If false,
0406:             * no extra work is done.  (This value is false whenever the
0407:             * formatter isn't in lenient-parse mode, but is also false
0408:             * under some conditions even when the formatter _is_ in
0409:             * lenient-parse mode.)
0410:             * @return If there's a match, this is the result of composing
0411:             * baseValue with whatever was returned from matching the
0412:             * characters.  This will be either a Long or a Double.  If there's
0413:             * no match this is new Long(0) (not null), and parsePosition
0414:             * is left unchanged.
0415:             */
0416:            public Number doParse(String text, ParsePosition parsePosition,
0417:                    double baseValue, double upperBound, boolean lenientParse) {
0418:                Number tempResult;
0419:
0420:                // figure out the highest base value a rule can have and match
0421:                // the text being parsed (this varies according to the type of
0422:                // substitutions: multiplier, modulus, and numerator substitutions
0423:                // restrict the search to rules with base values lower than their
0424:                // own; same-value substitutions leave the upper bound wherever
0425:                // it was, and the others allow any rule to match
0426:                upperBound = calcUpperBound(upperBound);
0427:
0428:                // use our rule set to parse the text.  If that fails and
0429:                // lenient parsing is enabled (this is always false if the
0430:                // formatter's lenient-parsing mode is off, but it may also
0431:                // be false even when the formatter's lenient-parse mode is
0432:                // on), then also try parsing the text using a default-
0433:                // constructed NumberFormat
0434:                if (ruleSet != null) {
0435:                    tempResult = ruleSet.parse(text, parsePosition, upperBound);
0436:                    if (lenientParse && !ruleSet.isFractionSet()
0437:                            && parsePosition.getIndex() == 0) {
0438:                        tempResult = NumberFormat.getInstance().parse(text,
0439:                                parsePosition);
0440:                    }
0441:
0442:                    // ...or use our DecimalFormat to parse the text
0443:                } else {
0444:                    tempResult = numberFormat.parse(text, parsePosition);
0445:                }
0446:
0447:                // if the parse was successful, we've already advanced the caller's
0448:                // parse position (this is the one function that doesn't have one
0449:                // of its own).  Derive a parse result and return it as a Long,
0450:                // if possible, or a Double
0451:                if (parsePosition.getIndex() != 0) {
0452:                    double result = tempResult.doubleValue();
0453:
0454:                    // composeRuleValue() produces a full parse result from
0455:                    // the partial parse result passed to this function from
0456:                    // the caller (this is either the owning rule's base value
0457:                    // or the partial result obtained from composing the
0458:                    // owning rule's base value with its other substitution's
0459:                    // parse result) and the partial parse result obtained by
0460:                    // matching the substitution (which will be the same value
0461:                    // the caller would get by parsing just this part of the
0462:                    // text with RuleBasedNumberFormat.parse() ).  How the two
0463:                    // values are used to derive the full parse result depends
0464:                    // on the types of substitutions: For a regular rule, the
0465:                    // ultimate result is its multiplier substitution's result
0466:                    // times the rule's divisor (or the rule's base value) plus
0467:                    // the modulus substitution's result (which will actually
0468:                    // supersede part of the rule's base value).  For a negative-
0469:                    // number rule, the result is the negative of its substitution's
0470:                    // result.  For a fraction rule, it's the sum of its two
0471:                    // substitution results.  For a rule in a fraction rule set,
0472:                    // it's the numerator substitution's result divided by
0473:                    // the rule's base value.  Results from same-value substitutions
0474:                    // propagate back upard, and null substitutions don't affect
0475:                    // the result.
0476:                    result = composeRuleValue(result, baseValue);
0477:                    if (result == (long) result) {
0478:                        return new Long((long) result);
0479:                    } else {
0480:                        return new Double(result);
0481:                    }
0482:
0483:                    // if the parse was UNsuccessful, return 0
0484:                } else {
0485:                    return tempResult;
0486:                }
0487:            }
0488:
0489:            /**
0490:             * Derives a new value from the two values passed in.  The two values
0491:             * are typically either the base values of two rules (the one containing
0492:             * the substitution and the one matching the substitution) or partial
0493:             * parse results derived in some other way.  The operation is generally
0494:             * the inverse of the operation performed by transformNumber().
0495:             * @param newRuleValue The value produced by matching this substitution
0496:             * @param oldRuleValue The value that was passed to the substitution
0497:             * by the rule that owns it
0498:             * @return A third value derived from the other two, representing a
0499:             * partial parse result
0500:             */
0501:            public abstract double composeRuleValue(double newRuleValue,
0502:                    double oldRuleValue);
0503:
0504:            /**
0505:             * Calculates an upper bound when searching for a rule that matches
0506:             * this substitution.  Rules with base values greater than or equal
0507:             * to upperBound are not considered.
0508:             * @param oldUpperBound The current upper-bound setting.  The new
0509:             * upper bound can't be any higher.
0510:             */
0511:            public abstract double calcUpperBound(double oldUpperBound);
0512:
0513:            //-----------------------------------------------------------------------
0514:            // simple accessors
0515:            //-----------------------------------------------------------------------
0516:
0517:            /**
0518:             * Returns the substitution's position in the rule that owns it.
0519:             * @return The substitution's position in the rule that owns it.
0520:             */
0521:            public final int getPos() {
0522:                return pos;
0523:            }
0524:
0525:            /**
0526:             * Returns the character used in the textual representation of
0527:             * substitutions of this type.  Used by toString().
0528:             * @return This substitution's token character.
0529:             */
0530:            abstract char tokenChar();
0531:
0532:            /**
0533:             * Returns true if this is a null substitution.  (We didn't do this
0534:             * with instanceof partially because it causes source files to
0535:             * proliferate and partially because we have to port this to C++.)
0536:             * @return true if this object is an instance of NullSubstitution
0537:             */
0538:            public boolean isNullSubstitution() {
0539:                return false;
0540:            }
0541:
0542:            /**
0543:             * Returns true if this is a modulus substitution.  (We didn't do this
0544:             * with instanceof partially because it causes source files to
0545:             * proliferate and partially because we have to port this to C++.)
0546:             * @return true if this object is an instance of ModulusSubstitution
0547:             */
0548:            public boolean isModulusSubstitution() {
0549:                return false;
0550:            }
0551:        }
0552:
0553:        //===================================================================
0554:        // SameValueSubstitution
0555:        //===================================================================
0556:
0557:        /**
0558:         * A substitution that passes the value passed to it through unchanged.
0559:         * Represented by == in rule descriptions.
0560:         */
0561:        class SameValueSubstitution extends NFSubstitution {
0562:            //-----------------------------------------------------------------------
0563:            // constants
0564:            //-----------------------------------------------------------------------
0565:
0566:            /**
0567:             * Puts a copyright in the .class file
0568:             */
0569:            private static final String copyrightNotice = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
0570:
0571:            //-----------------------------------------------------------------------
0572:            // construction
0573:            //-----------------------------------------------------------------------
0574:
0575:            /**
0576:             * Constructs a SameValueSubstution.  This function just uses the
0577:             * superclass constructor, but it performs a check that this
0578:             * substitution doesn't call the rule set that owns it, since that
0579:             * would lead to infinite recursion.
0580:             */
0581:            SameValueSubstitution(int pos, NFRuleSet ruleSet,
0582:                    RuleBasedNumberFormat formatter, String description) {
0583:                super (pos, ruleSet, formatter, description);
0584:                if (description.equals("==")) {
0585:                    throw new IllegalArgumentException(
0586:                            "== is not a legal token");
0587:                }
0588:            }
0589:
0590:            //-----------------------------------------------------------------------
0591:            // formatting
0592:            //-----------------------------------------------------------------------
0593:
0594:            /**
0595:             * Returns "number" unchanged.
0596:             * @return "number"
0597:             */
0598:            public long transformNumber(long number) {
0599:                return number;
0600:            }
0601:
0602:            /**
0603:             * Returns "number" unchanged.
0604:             * @return "number"
0605:             */
0606:            public double transformNumber(double number) {
0607:                return number;
0608:            }
0609:
0610:            //-----------------------------------------------------------------------
0611:            // parsing
0612:            //-----------------------------------------------------------------------
0613:
0614:            /**
0615:             * Returns newRuleValue and ignores oldRuleValue. (The value we got
0616:             * matching the substitution supersedes the value of the rule
0617:             * that owns the substitution.)
0618:             * @param newRuleValue The value resulting from matching the substituion
0619:             * @param oldRuleValue The value of the rule containing the
0620:             * substitution.
0621:             * @return newRuleValue
0622:             */
0623:            public double composeRuleValue(double newRuleValue,
0624:                    double oldRuleValue) {
0625:                return newRuleValue;
0626:            }
0627:
0628:            /**
0629:             * SameValueSubstitution doesn't change the upper bound.
0630:             * @param oldUpperBound The current upper bound.
0631:             * @return oldUpperBound
0632:             */
0633:            public double calcUpperBound(double oldUpperBound) {
0634:                return oldUpperBound;
0635:            }
0636:
0637:            //-----------------------------------------------------------------------
0638:            // simple accessor
0639:            //-----------------------------------------------------------------------
0640:
0641:            /**
0642:             * The token character for a SameValueSubstitution is =.
0643:             * @return '='
0644:             */
0645:            char tokenChar() {
0646:                return '=';
0647:            }
0648:        }
0649:
0650:        //===================================================================
0651:        // MultiplierSubstitution
0652:        //===================================================================
0653:
0654:        /**
0655:         * A substitution that divides the number being formatted by the rule's
0656:         * divisor and formats the quotient.  Represented by &lt;&lt; in normal
0657:         * rules.
0658:         */
0659:        class MultiplierSubstitution extends NFSubstitution {
0660:            //-----------------------------------------------------------------------
0661:            // constants
0662:            //-----------------------------------------------------------------------
0663:
0664:            /**
0665:             * Puts a copyright in the .class file
0666:             */
0667:            private static final String copyrightNotice = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
0668:
0669:            //-----------------------------------------------------------------------
0670:            // data members
0671:            //-----------------------------------------------------------------------
0672:
0673:            /**
0674:             * The divisor of the rule that owns this substitution.
0675:             */
0676:            double divisor;
0677:
0678:            //-----------------------------------------------------------------------
0679:            // construction
0680:            //-----------------------------------------------------------------------
0681:
0682:            /**
0683:             * Constructs a MultiplierSubstitution.  This uses the superclass
0684:             * constructor to initialize most members, but this substitution
0685:             * also maintains its own copy of its rule's divisor.
0686:             * @param pos The substitution's position in its rule's rule text
0687:             * @param divisor The owning rule's divisor
0688:             * @ruleSet The ruleSet this substitution uses to format its result
0689:             * @formatter The formatter that owns this substitution
0690:             * @description The description describing this substitution
0691:             */
0692:            MultiplierSubstitution(int pos, double divisor, NFRuleSet ruleSet,
0693:                    RuleBasedNumberFormat formatter, String description) {
0694:                super (pos, ruleSet, formatter, description);
0695:
0696:                // the owning rule's divisor affects the behavior of this
0697:                // substitution.  Rather than keeping a back-pointer to the
0698:                // rule, we keep a copy of the divisor
0699:                this .divisor = divisor;
0700:
0701:                if (divisor == 0) { // this will cause recursion
0702:                    throw new IllegalStateException(
0703:                            "Substitution with bad divisor (" + divisor + ") "
0704:                                    + description.substring(0, pos) + " | "
0705:                                    + description.substring(pos));
0706:                }
0707:            }
0708:
0709:            /**
0710:             * Sets the substitution's divisor based on the values passed in.
0711:             * @param radix The radix of the divisor.
0712:             * @param exponent The exponent of the divisor.
0713:             */
0714:            public void setDivisor(int radix, int exponent) {
0715:                divisor = Math.pow(radix, exponent);
0716:
0717:                if (divisor == 0) {
0718:                    throw new IllegalStateException(
0719:                            "Substitution with divisor 0");
0720:                }
0721:            }
0722:
0723:            //-----------------------------------------------------------------------
0724:            // boilerplate
0725:            //-----------------------------------------------------------------------
0726:
0727:            /**
0728:             * Augments the superclass's equals() function by comparing divisors.
0729:             * @param that The other substitution
0730:             * @return true if the two substitutions are functionally equal
0731:             */
0732:            public boolean equals(Object that) {
0733:                if (super .equals(that)) {
0734:                    MultiplierSubstitution that2 = (MultiplierSubstitution) that;
0735:
0736:                    return divisor == that2.divisor;
0737:                } else {
0738:                    return false;
0739:                }
0740:            }
0741:
0742:            //-----------------------------------------------------------------------
0743:            // formatting
0744:            //-----------------------------------------------------------------------
0745:
0746:            /**
0747:             * Divides the number by the rule's divisor and returns the quotient.
0748:             * @param number The number being formatted.
0749:             * @return "number" divided by the rule's divisor
0750:             */
0751:            public long transformNumber(long number) {
0752:                return (long) Math.floor(number / divisor);
0753:            }
0754:
0755:            /**
0756:             * Divides the number by the rule's divisor and returns the quotient.
0757:             * This is an integral quotient if we're filling in the substitution
0758:             * using another rule set, but it's the full quotient (integral and
0759:             * fractional parts) if we're filling in the substitution using
0760:             * a DecimalFormat.  (This allows things such as "1.2 million".)
0761:             * @param number The number being formatted
0762:             * @return "number" divided by the rule's divisor
0763:             */
0764:            public double transformNumber(double number) {
0765:                if (ruleSet == null) {
0766:                    return number / divisor;
0767:                } else {
0768:                    return Math.floor(number / divisor);
0769:                }
0770:            }
0771:
0772:            //-----------------------------------------------------------------------
0773:            // parsing
0774:            //-----------------------------------------------------------------------
0775:
0776:            /**
0777:             * Returns newRuleValue times the divisor.  Ignores oldRuleValue.
0778:             * (The result of matching a << substitution supersedes the base
0779:             * value of the rule that contains it.)
0780:             * @param newRuleValue The result of matching the substitution
0781:             * @param oldRuleValue The base value of the rule containing the
0782:             * substitution
0783:             * @return newRuleValue * divisor
0784:             */
0785:            public double composeRuleValue(double newRuleValue,
0786:                    double oldRuleValue) {
0787:                return newRuleValue * divisor;
0788:            }
0789:
0790:            /**
0791:             * Sets the upper bound down to the rule's divisor.
0792:             * @param oldUpperBound Ignored.
0793:             * @return The rule's divisor.
0794:             */
0795:            public double calcUpperBound(double oldUpperBound) {
0796:                return divisor;
0797:            }
0798:
0799:            //-----------------------------------------------------------------------
0800:            // simple accessor
0801:            //-----------------------------------------------------------------------
0802:
0803:            /**
0804:             * The token character for a multiplier substitution is &lt;.
0805:             * @return '&lt;'
0806:             */
0807:            char tokenChar() {
0808:                return '<';
0809:            }
0810:        }
0811:
0812:        //===================================================================
0813:        // ModulusSubstitution
0814:        //===================================================================
0815:
0816:        /**
0817:         * A substitution that divides the number being formatted by the its rule's
0818:         * divisor and formats the remainder.  Represented by "&gt;&gt;" in a
0819:         * regular rule.
0820:         */
0821:        class ModulusSubstitution extends NFSubstitution {
0822:            //-----------------------------------------------------------------------
0823:            // constants
0824:            //-----------------------------------------------------------------------
0825:
0826:            /**
0827:             * Puts a copyright in the .class file
0828:             */
0829:            private static final String copyrightNotice = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
0830:
0831:            //-----------------------------------------------------------------------
0832:            // data members
0833:            //-----------------------------------------------------------------------
0834:
0835:            /**
0836:             * The divisor of the rule owning this substitution
0837:             */
0838:            double divisor;
0839:
0840:            /**
0841:             * If this is a &gt;&gt;&gt; substitution, the rule to use to format
0842:             * the substitution value.  Otherwise, null.
0843:             */
0844:            NFRule ruleToUse;
0845:
0846:            //-----------------------------------------------------------------------
0847:            // construction
0848:            //-----------------------------------------------------------------------
0849:
0850:            /**
0851:             * Constructs a ModulusSubstution.  In addition to the inherited
0852:             * members, a ModulusSubstitution keeps track of the divisor of the
0853:             * rule that owns it, and may also keep a reference to the rule
0854:             * that precedes the rule containing this substitution in the rule
0855:             * set's rule list.
0856:             * @param pos The substitution's position in its rule's rule text
0857:             * @param divisor The divisor of the rule that owns this substitution
0858:             * @param rulePredecessor The rule that precedes this substitution's
0859:             * rule in its rule set's rule list
0860:             * @param formatter The RuleBasedNumberFormat owning this substitution
0861:             * @param description The description for this substitution
0862:             */
0863:            ModulusSubstitution(int pos, double divisor,
0864:                    NFRule rulePredecessor, NFRuleSet ruleSet,
0865:                    RuleBasedNumberFormat formatter, String description) {
0866:                super (pos, ruleSet, formatter, description);
0867:
0868:                // the owning rule's divisor controls the behavior of this
0869:                // substitution: rather than keeping a backpointer to the rule,
0870:                // we keep a copy of the divisor
0871:                this .divisor = divisor;
0872:
0873:                if (divisor == 0) { // this will cause recursion
0874:                    throw new IllegalStateException(
0875:                            "Substitution with bad divisor (" + divisor + ") "
0876:                                    + description.substring(0, pos) + " | "
0877:                                    + description.substring(pos));
0878:                }
0879:
0880:                // the >>> token doesn't alter how this substituion calculates the
0881:                // values it uses for formatting and parsing, but it changes
0882:                // what's done with that value after it's obtained: >>> short-
0883:                // circuits the rule-search process and goes straight to the
0884:                // specified rule to format the substitution value
0885:                if (description.equals(">>>")) {
0886:                    ruleToUse = rulePredecessor;
0887:                } else {
0888:                    ruleToUse = null;
0889:                }
0890:            }
0891:
0892:            /**
0893:             * Makes the substitution's divisor conform to that of the rule
0894:             * that owns it.  Used when the divisor is determined after creation.
0895:             * @param radix The radix of the divsor.
0896:             * @param exponent The exponent of the divisor.
0897:             */
0898:            public void setDivisor(int radix, int exponent) {
0899:                divisor = Math.pow(radix, exponent);
0900:
0901:                if (divisor == 0) { // this will cause recursion
0902:                    throw new IllegalStateException(
0903:                            "Substitution with bad divisor");
0904:                }
0905:            }
0906:
0907:            //-----------------------------------------------------------------------
0908:            // boilerplate
0909:            //-----------------------------------------------------------------------
0910:
0911:            /**
0912:             * Augments the inherited equals() function by comparing divisors and
0913:             * ruleToUse.
0914:             * @param that The other substitution
0915:             * @return true if the two substitutions are functionally equivalent
0916:             */
0917:            public boolean equals(Object that) {
0918:                if (super .equals(that)) {
0919:                    ModulusSubstitution that2 = (ModulusSubstitution) that;
0920:
0921:                    return divisor == that2.divisor;
0922:                } else {
0923:                    return false;
0924:                }
0925:            }
0926:
0927:            //-----------------------------------------------------------------------
0928:            // formatting
0929:            //-----------------------------------------------------------------------
0930:
0931:            /**
0932:             * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
0933:             * the substitution.  Otherwise, just use the superclass function.
0934:             * @param number The number being formatted
0935:             * @toInsertInto The string to insert the result of this substitution
0936:             * into
0937:             * @param pos The position of the rule text in toInsertInto
0938:             */
0939:            public void doSubstitution(long number, StringBuffer toInsertInto,
0940:                    int pos) {
0941:                // if this isn't a >>> substitution, just use the inherited version
0942:                // of this function (which uses either a rule set or a DecimalFormat
0943:                // to format its substitution value)
0944:                if (ruleToUse == null) {
0945:                    super .doSubstitution(number, toInsertInto, pos);
0946:
0947:                    // a >>> substitution goes straight to a particular rule to
0948:                    // format the substitution value
0949:                } else {
0950:                    long numberToFormat = transformNumber(number);
0951:                    ruleToUse.doFormat(numberToFormat, toInsertInto, pos
0952:                            + this .pos);
0953:                }
0954:            }
0955:
0956:            /**
0957:             * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
0958:             * the substitution.  Otherwise, just use the superclass function.
0959:             * @param number The number being formatted
0960:             * @toInsertInto The string to insert the result of this substitution
0961:             * into
0962:             * @param pos The position of the rule text in toInsertInto
0963:             */
0964:            public void doSubstitution(double number,
0965:                    StringBuffer toInsertInto, int pos) {
0966:                // if this isn't a >>> substitution, just use the inherited version
0967:                // of this function (which uses either a rule set or a DecimalFormat
0968:                // to format its substitution value)
0969:                if (ruleToUse == null) {
0970:                    super .doSubstitution(number, toInsertInto, pos);
0971:
0972:                    // a >>> substitution goes straight to a particular rule to
0973:                    // format the substitution value
0974:                } else {
0975:                    double numberToFormat = transformNumber(number);
0976:
0977:                    ruleToUse.doFormat(numberToFormat, toInsertInto, pos
0978:                            + this .pos);
0979:                }
0980:            }
0981:
0982:            /**
0983:             * Divides the number being formatted by the rule's divisor and
0984:             * returns the remainder.
0985:             * @param number The number being formatted
0986:             * @return "number" mod divisor
0987:             */
0988:            public long transformNumber(long number) {
0989:                return (long) Math.floor(number % divisor);
0990:            }
0991:
0992:            /**
0993:             * Divides the number being formatted by the rule's divisor and
0994:             * returns the remainder.
0995:             * @param number The number being formatted
0996:             * @return "number" mod divisor
0997:             */
0998:            public double transformNumber(double number) {
0999:                return Math.floor(number % divisor);
1000:            }
1001:
1002:            //-----------------------------------------------------------------------
1003:            // parsing
1004:            //-----------------------------------------------------------------------
1005:
1006:            /**
1007:             * If this is a &gt;&gt;&gt; substitution, match only against ruleToUse.
1008:             * Otherwise, use the superclass function.
1009:             * @param text The string to parse
1010:             * @param parsePosition Ignored on entry, updated on exit to point to
1011:             * the first unmatched character.
1012:             * @param baseValue The partial parse result prior to calling this
1013:             * routine.
1014:             */
1015:            public Number doParse(String text, ParsePosition parsePosition,
1016:                    double baseValue, double upperBound, boolean lenientParse) {
1017:                // if this isn't a >>> substitution, we can just use the
1018:                // inherited parse() routine to do the parsing
1019:                if (ruleToUse == null) {
1020:                    return super .doParse(text, parsePosition, baseValue,
1021:                            upperBound, lenientParse);
1022:
1023:                    // but if it IS a >>> substitution, we have to do it here: we
1024:                    // use the specific rule's doParse() method, and then we have to
1025:                    // do some of the other work of NFRuleSet.parse()
1026:                } else {
1027:                    Number tempResult = ruleToUse.doParse(text, parsePosition,
1028:                            false, upperBound);
1029:
1030:                    if (parsePosition.getIndex() != 0) {
1031:                        double result = tempResult.doubleValue();
1032:
1033:                        result = composeRuleValue(result, baseValue);
1034:                        if (result == (long) result) {
1035:                            return new Long((long) result);
1036:                        } else {
1037:                            return new Double(result);
1038:                        }
1039:                    } else {
1040:                        return tempResult;
1041:                    }
1042:                }
1043:            }
1044:
1045:            /**
1046:             * Returns the highest multiple of the rule's divisor that its less
1047:             * than or equal to oldRuleValue, plus newRuleValue.  (The result
1048:             * is the sum of the result of parsing the substitution plus the
1049:             * base valueof the rule containing the substitution, but if the
1050:             * owning rule's base value isn't an even multiple of its divisor,
1051:             * we have to round it down to a multiple of the divisor, or we
1052:             * get unwanted digits in the result.)
1053:             * @param newRuleValue The result of parsing the substitution
1054:             * @param oldRuleValue The base value of the rule containing the
1055:             * substitution
1056:             * @return (oldRuleValue - (oldRuleValue % divisor)) + newRuleValue
1057:             */
1058:            public double composeRuleValue(double newRuleValue,
1059:                    double oldRuleValue) {
1060:                return (oldRuleValue - (oldRuleValue % divisor)) + newRuleValue;
1061:            }
1062:
1063:            /**
1064:             * Sets the upper bound down to the owning rule's divisor
1065:             * @param oldUpperBound Ignored
1066:             * @return The owning rule's dvisor
1067:             */
1068:            public double calcUpperBound(double oldUpperBound) {
1069:                return divisor;
1070:            }
1071:
1072:            //-----------------------------------------------------------------------
1073:            // simple accessors
1074:            //-----------------------------------------------------------------------
1075:
1076:            /**
1077:             * Returns true.  This _is_ a ModulusSubstitution.
1078:             * @return true
1079:             */
1080:            public boolean isModulusSubstitution() {
1081:                return true;
1082:            }
1083:
1084:            /**
1085:             * The token character of a ModulusSubstitution is &gt;.
1086:             * @return '&gt;'
1087:             */
1088:            char tokenChar() {
1089:                return '>';
1090:            }
1091:        }
1092:
1093:        //===================================================================
1094:        // IntegralPartSubstitution
1095:        //===================================================================
1096:
1097:        /**
1098:         * A substitution that formats the number's integral part.  This is
1099:         * represented by &lt;&lt; in a fraction rule.
1100:         */
1101:        class IntegralPartSubstitution extends NFSubstitution {
1102:            //-----------------------------------------------------------------------
1103:            // constants
1104:            //-----------------------------------------------------------------------
1105:
1106:            /**
1107:             * Puts a copyright in the .class file
1108:             */
1109:            private static final String copyrightNotice = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
1110:
1111:            //-----------------------------------------------------------------------
1112:            // construction
1113:            //-----------------------------------------------------------------------
1114:
1115:            /**
1116:             * Constructs an IntegralPartSubstitution.  This just calls
1117:             * the superclass constructor.
1118:             */
1119:            IntegralPartSubstitution(int pos, NFRuleSet ruleSet,
1120:                    RuleBasedNumberFormat formatter, String description) {
1121:                super (pos, ruleSet, formatter, description);
1122:            }
1123:
1124:            //-----------------------------------------------------------------------
1125:            // formatting
1126:            //-----------------------------------------------------------------------
1127:
1128:            /**
1129:             * Returns the number's integral part. (For a long, that's just the
1130:             * number unchanged.)
1131:             * @param number The number being formatted
1132:             * @return "number" unchanged
1133:             */
1134:            public long transformNumber(long number) {
1135:                return number;
1136:            }
1137:
1138:            /**
1139:             * Returns the number's integral part.
1140:             * @param number The integral part of the number being formatted
1141:             * @return floor(number)
1142:             */
1143:            public double transformNumber(double number) {
1144:                return Math.floor(number);
1145:            }
1146:
1147:            //-----------------------------------------------------------------------
1148:            // parsing
1149:            //-----------------------------------------------------------------------
1150:
1151:            /**
1152:             * Returns the sum of the result of parsing the substitution and the
1153:             * owning rule's base value.  (The owning rule, at best, has an
1154:             * integral-part substitution and a fractional-part substitution,
1155:             * so we can safely just add them.)
1156:             * @param newRuleValue The result of matching the substitution
1157:             * @param oldRuleValue The partial result of the parse prior to
1158:             * calling this function
1159:             * @return oldRuleValue + newRuleValue
1160:             */
1161:            public double composeRuleValue(double newRuleValue,
1162:                    double oldRuleValue) {
1163:                return newRuleValue + oldRuleValue;
1164:            }
1165:
1166:            /**
1167:             * An IntegralPartSubstitution sets the upper bound back up so all
1168:             * potentially matching rules are considered.
1169:             * @param oldUpperBound Ignored
1170:             * @return Double.MAX_VALUE
1171:             */
1172:            public double calcUpperBound(double oldUpperBound) {
1173:                return Double.MAX_VALUE;
1174:            }
1175:
1176:            //-----------------------------------------------------------------------
1177:            // simple accessor
1178:            //-----------------------------------------------------------------------
1179:
1180:            /**
1181:             * An IntegralPartSubstitution's token character is &lt;
1182:             * @return '&lt;'
1183:             */
1184:            char tokenChar() {
1185:                return '<';
1186:            }
1187:        }
1188:
1189:        //===================================================================
1190:        // FractionalPartSubstitution
1191:        //===================================================================
1192:
1193:        /**
1194:         * A substitution that formats the fractional part of a number.  This is
1195:         * represented by &gt;&gt; in a fraction rule.
1196:         */
1197:        class FractionalPartSubstitution extends NFSubstitution {
1198:            //-----------------------------------------------------------------------
1199:            // constants
1200:            //-----------------------------------------------------------------------
1201:
1202:            /**
1203:             * Puts a copyright in the .class file
1204:             */
1205:            private static final String copyrightNotice = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
1206:
1207:            //-----------------------------------------------------------------------
1208:            // data members
1209:            //-----------------------------------------------------------------------
1210:
1211:            /**
1212:             * true if this substitution should have the default "by digits"
1213:             * behavior, false otherwise
1214:             */
1215:            private boolean byDigits = false;
1216:
1217:            /**
1218:             * true if we automatically insert spaces to separate names of digits
1219:             * set to false by '>>>' in fraction rules, used by Thai.
1220:             */
1221:            private boolean useSpaces = true;
1222:
1223:            /**
1224:             * The largest number of digits after the decimal point that this
1225:             * object will show in "by digits" mode
1226:             */
1227:            private static final int MAXDECIMALDIGITS = 18; // 8
1228:
1229:            //-----------------------------------------------------------------------
1230:            // construction
1231:            //-----------------------------------------------------------------------
1232:
1233:            /**
1234:             * Constructs a FractionalPartSubstitution.  This object keeps a flag
1235:             * telling whether it should format by digits or not.  In addition,
1236:             * it marks the rule set it calls (if any) as a fraction rule set.
1237:             */
1238:            FractionalPartSubstitution(int pos, NFRuleSet ruleSet,
1239:                    RuleBasedNumberFormat formatter, String description) {
1240:                super (pos, ruleSet, formatter, description);
1241:                //    boolean chevron = description.startsWith(">>") || ruleSet == this.ruleSet;
1242:                //      if (chevron || ruleSet == this.ruleSet) {
1243:
1244:                if (description.equals(">>") || description.equals(">>>")
1245:                        || ruleSet == this .ruleSet) {
1246:                    byDigits = true;
1247:                    if (description.equals(">>>")) {
1248:                        useSpaces = false;
1249:                    }
1250:                } else {
1251:                    this .ruleSet.makeIntoFractionRuleSet();
1252:                }
1253:            }
1254:
1255:            //-----------------------------------------------------------------------
1256:            // formatting
1257:            //-----------------------------------------------------------------------
1258:
1259:            /**
1260:             * If in "by digits" mode, fills in the substitution one decimal digit
1261:             * at a time using the rule set containing this substitution.
1262:             * Otherwise, uses the superclass function.
1263:             * @param number The number being formatted
1264:             * @param toInsertInto The string to insert the result of formatting
1265:             * the substitution into
1266:             * @param pos The position of the owning rule's rule text in
1267:             * toInsertInto
1268:             */
1269:            public void doSubstitution(double number,
1270:                    StringBuffer toInsertInto, int pos) {
1271:                // if we're not in "byDigits" mode, just use the inherited
1272:                // doSubstitution() routine
1273:                if (!byDigits) {
1274:                    super .doSubstitution(number, toInsertInto, pos);
1275:
1276:                    // if we're in "byDigits" mode, transform the value into an integer
1277:                    // by moving the decimal point eight places to the right and
1278:                    // pulling digits off the right one at a time, formatting each digit
1279:                    // as an integer using this substitution's owning rule set
1280:                    // (this is slower, but more accurate, than doing it from the
1281:                    // other end)
1282:                } else {
1283:                    //              int numberToFormat = (int)Math.round(transformNumber(number) * Math.pow(
1284:                    //                              10, MAXDECIMALDIGITS));
1285:                    //        long numberToFormat = (long)Math.round(transformNumber(number) * Math.pow(10, MAXDECIMALDIGITS));
1286:
1287:                    // just print to string and then use that
1288:                    DigitList dl = new DigitList();
1289:                    dl.set(number, 20, true);
1290:
1291:                    // this flag keeps us from formatting trailing zeros.  It starts
1292:                    // out false because we're pulling from the right, and switches
1293:                    // to true the first time we encounter a non-zero digit
1294:                    //              boolean doZeros = false;
1295:                    //          System.out.println("class: " + getClass().getName());
1296:                    //          System.out.println("number: " + number + " transformed: " + transformNumber(number));
1297:                    //          System.out.println("formatting " + numberToFormat);
1298:                    //              for (int i = 0; i < MAXDECIMALDIGITS; i++) {
1299:                    //                  int digit = (int)(numberToFormat % 10);
1300:                    //          System.out.println("   #: '" + numberToFormat + "'" + " digit '" + digit + "'");
1301:                    //                  if (digit != 0 || doZeros) {
1302:                    //                      if (doZeros && useSpaces) {
1303:                    //                          toInsertInto.insert(pos + this.pos, ' ');
1304:                    //                      }
1305:                    //                      doZeros = true;
1306:                    //                      ruleSet.format(digit, toInsertInto, pos + this.pos);
1307:                    //                  }
1308:                    //                  numberToFormat /= 10;
1309:                    //              }
1310:
1311:                    boolean pad = false;
1312:                    while (dl.count > Math.max(0, dl.decimalAt)) {
1313:                        if (pad && useSpaces) {
1314:                            toInsertInto.insert(pos + this .pos, ' ');
1315:                        } else {
1316:                            pad = true;
1317:                        }
1318:                        ruleSet.format(dl.digits[--dl.count] - '0',
1319:                                toInsertInto, pos + this .pos);
1320:                    }
1321:                    while (dl.decimalAt < 0) {
1322:                        if (pad && useSpaces) {
1323:                            toInsertInto.insert(pos + this .pos, ' ');
1324:                        } else {
1325:                            pad = true;
1326:                        }
1327:                        ruleSet.format(0, toInsertInto, pos + this .pos);
1328:                        ++dl.decimalAt;
1329:                    }
1330:                }
1331:            }
1332:
1333:            /**
1334:             * Returns the fractional part of the number, which will always be
1335:             * zero if it's a long.
1336:             * @param number The number being formatted
1337:             * @return 0
1338:             */
1339:            public long transformNumber(long number) {
1340:                return 0;
1341:            }
1342:
1343:            /**
1344:             * Returns the fractional part of the number.
1345:             * @param number The number being formatted.
1346:             * @return number - floor(number)
1347:             */
1348:            public double transformNumber(double number) {
1349:                return number - Math.floor(number);
1350:            }
1351:
1352:            //-----------------------------------------------------------------------
1353:            // parsing
1354:            //-----------------------------------------------------------------------
1355:
1356:            /**
1357:             * If in "by digits" mode, parses the string as if it were a string
1358:             * of individual digits; otherwise, uses the superclass function.
1359:             * @param text The string to parse
1360:             * @param parsePosition Ignored on entry, but updated on exit to point
1361:             * to the first unmatched character
1362:             * @param baseValue The partial parse result prior to entering this
1363:             * function
1364:             * @param upperBound Only consider rules with base values lower than
1365:             * this when filling in the substitution
1366:             * @param lenientParse If true, try matching the text as numerals if
1367:             * matching as words doesn't work
1368:             * @return If the match was successful, the current partial parse
1369:             * result; otherwise new Long(0).  The result is either a Long or
1370:             * a Double.
1371:             */
1372:            public Number doParse(String text, ParsePosition parsePosition,
1373:                    double baseValue, double upperBound, boolean lenientParse) {
1374:                // if we're not in byDigits mode, we can just use the inherited
1375:                // doParse()
1376:                if (!byDigits) {
1377:                    return super .doParse(text, parsePosition, baseValue, 0,
1378:                            lenientParse);
1379:
1380:                    // if we ARE in byDigits mode, parse the text one digit at a time
1381:                    // using this substitution's owning rule set (we do this by setting
1382:                    // upperBound to 10 when calling doParse() ) until we reach
1383:                    // nonmatching text
1384:                } else {
1385:                    String workText = new String(text);
1386:                    ParsePosition workPos = new ParsePosition(1);
1387:                    double result = 0;
1388:                    int digit;
1389:                    //              double p10 = 0.1;
1390:
1391:                    //              while (workText.length() > 0 && workPos.getIndex() != 0) {
1392:                    //                  workPos.setIndex(0);
1393:                    //                  digit = ruleSet.parse(workText, workPos, 10).intValue();
1394:                    //                  if (lenientParse && workPos.getIndex() == 0) {
1395:                    //                      digit = NumberFormat.getInstance().parse(workText, workPos).intValue();
1396:                    //                  }
1397:
1398:                    //                  if (workPos.getIndex() != 0) {
1399:                    //                      result += digit * p10;
1400:                    //                      p10 /= 10;
1401:                    //                      parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
1402:                    //                      workText = workText.substring(workPos.getIndex());
1403:                    //                      while (workText.length() > 0 && workText.charAt(0) == ' ') {
1404:                    //                          workText = workText.substring(1);
1405:                    //                          parsePosition.setIndex(parsePosition.getIndex() + 1);
1406:                    //                      }
1407:                    //                  }
1408:                    //              }
1409:
1410:                    DigitList dl = new DigitList();
1411:                    while (workText.length() > 0 && workPos.getIndex() != 0) {
1412:                        workPos.setIndex(0);
1413:                        digit = ruleSet.parse(workText, workPos, 10).intValue();
1414:                        if (lenientParse && workPos.getIndex() == 0) {
1415:                            digit = NumberFormat.getInstance().parse(workText,
1416:                                    workPos).intValue();
1417:                        }
1418:
1419:                        if (workPos.getIndex() != 0) {
1420:                            dl.append('0' + digit);
1421:
1422:                            parsePosition.setIndex(parsePosition.getIndex()
1423:                                    + workPos.getIndex());
1424:                            workText = workText.substring(workPos.getIndex());
1425:                            while (workText.length() > 0
1426:                                    && workText.charAt(0) == ' ') {
1427:                                workText = workText.substring(1);
1428:                                parsePosition
1429:                                        .setIndex(parsePosition.getIndex() + 1);
1430:                            }
1431:                        }
1432:                    }
1433:                    result = dl.count == 0 ? 0 : dl.getDouble();
1434:
1435:                    result = composeRuleValue(result, baseValue);
1436:                    return new Double(result);
1437:                }
1438:            }
1439:
1440:            /**
1441:             * Returns the sum of the two partial parse results.
1442:             * @param newRuleValue The result of parsing the substitution
1443:             * @param oldRuleValue The partial parse result prior to calling
1444:             * this function
1445:             * @return newRuleValue + oldRuleValue
1446:             */
1447:            public double composeRuleValue(double newRuleValue,
1448:                    double oldRuleValue) {
1449:                return newRuleValue + oldRuleValue;
1450:            }
1451:
1452:            /**
1453:             * Not used.
1454:             */
1455:            public double calcUpperBound(double oldUpperBound) {
1456:                return 0; // this value is ignored
1457:            }
1458:
1459:            //-----------------------------------------------------------------------
1460:            // simple accessor
1461:            //-----------------------------------------------------------------------
1462:
1463:            /**
1464:             * The token character for a FractionalPartSubstitution is &gt;.
1465:             * @return '&gt;'
1466:             */
1467:            char tokenChar() {
1468:                return '>';
1469:            }
1470:        }
1471:
1472:        //===================================================================
1473:        // AbsoluteValueSubstitution
1474:        //===================================================================
1475:
1476:        /**
1477:         * A substitution that formats the absolute value of the number.
1478:         * This substition is represented by &gt;&gt; in a negative-number rule.
1479:         */
1480:        class AbsoluteValueSubstitution extends NFSubstitution {
1481:            //-----------------------------------------------------------------------
1482:            // constants
1483:            //-----------------------------------------------------------------------
1484:
1485:            /**
1486:             * Puts a copyright in the .class file
1487:             */
1488:            private static final String copyrightNotice = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
1489:
1490:            //-----------------------------------------------------------------------
1491:            // construction
1492:            //-----------------------------------------------------------------------
1493:
1494:            /**
1495:             * Constructs an AbsoluteValueSubstitution.  This just uses the
1496:             * superclass constructor.
1497:             */
1498:            AbsoluteValueSubstitution(int pos, NFRuleSet ruleSet,
1499:                    RuleBasedNumberFormat formatter, String description) {
1500:                super (pos, ruleSet, formatter, description);
1501:            }
1502:
1503:            //-----------------------------------------------------------------------
1504:            // formatting
1505:            //-----------------------------------------------------------------------
1506:
1507:            /**
1508:             * Returns the absolute value of the number.
1509:             * @param number The number being formatted.
1510:             * @return abs(number)
1511:             */
1512:            public long transformNumber(long number) {
1513:                return Math.abs(number);
1514:            }
1515:
1516:            /**
1517:             * Returns the absolute value of the number.
1518:             * @param number The number being formatted.
1519:             * @return abs(number)
1520:             */
1521:            public double transformNumber(double number) {
1522:                return Math.abs(number);
1523:            }
1524:
1525:            //-----------------------------------------------------------------------
1526:            // parsing
1527:            //-----------------------------------------------------------------------
1528:
1529:            /**
1530:             * Returns the addtive inverse of the result of parsing the
1531:             * substitution (this supersedes the earlier partial result)
1532:             * @param newRuleValue The result of parsing the substitution
1533:             * @param oldRuleValue The partial parse result prior to calling
1534:             * this function
1535:             * @return -newRuleValue
1536:             */
1537:            public double composeRuleValue(double newRuleValue,
1538:                    double oldRuleValue) {
1539:                return -newRuleValue;
1540:            }
1541:
1542:            /**
1543:             * Sets the upper bound beck up to consider all rules
1544:             * @param oldUpperBound Ignored.
1545:             * @return Double.MAX_VALUE
1546:             */
1547:            public double calcUpperBound(double oldUpperBound) {
1548:                return Double.MAX_VALUE;
1549:            }
1550:
1551:            //-----------------------------------------------------------------------
1552:            // simple accessor
1553:            //-----------------------------------------------------------------------
1554:
1555:            /**
1556:             * The token character for an AbsoluteValueSubstitution is &gt;
1557:             * @return '&gt;'
1558:             */
1559:            char tokenChar() {
1560:                return '>';
1561:            }
1562:        }
1563:
1564:        //===================================================================
1565:        // NumeratorSubstitution
1566:        //===================================================================
1567:
1568:        /**
1569:         * A substitution that multiplies the number being formatted (which is
1570:         * between 0 and 1) by the base value of the rule that owns it and
1571:         * formats the result.  It is represented by &lt;&lt; in the rules
1572:         * in a fraction rule set.
1573:         */
1574:        class NumeratorSubstitution extends NFSubstitution {
1575:            //-----------------------------------------------------------------------
1576:            // constants
1577:            //-----------------------------------------------------------------------
1578:
1579:            /**
1580:             * Puts a copyright in the .class file
1581:             */
1582:            private static final String copyrightNotice = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
1583:
1584:            //-----------------------------------------------------------------------
1585:            // data members
1586:            //-----------------------------------------------------------------------
1587:
1588:            /**
1589:             * The denominator of the fraction we're finding the numerator for.
1590:             * (The base value of the rule that owns this substitution.)
1591:             */
1592:            double denominator;
1593:
1594:            /**
1595:             * True if we format leading zeros (this is a hack for Hebrew spellout)
1596:             */
1597:            boolean withZeros;
1598:
1599:            //-----------------------------------------------------------------------
1600:            // construction
1601:            //-----------------------------------------------------------------------
1602:
1603:            /**
1604:             * Constructs a NumberatorSubstitution.  In addition to the inherited
1605:             * fields, a NumeratorSubstitution keeps track of a denominator, which
1606:             * is merely the base value of the rule that owns it.
1607:             */
1608:            NumeratorSubstitution(int pos, double denominator,
1609:                    NFRuleSet ruleSet, RuleBasedNumberFormat formatter,
1610:                    String description) {
1611:                super (pos, ruleSet, formatter, fixdesc(description));
1612:
1613:                // this substitution's behavior depends on the rule's base value
1614:                // Rather than keeping a backpointer to the rule, we copy its
1615:                // base value here
1616:                this .denominator = denominator;
1617:
1618:                this .withZeros = description.endsWith("<<");
1619:            }
1620:
1621:            static String fixdesc(String description) {
1622:                return description.endsWith("<<") ? description.substring(0,
1623:                        description.length() - 1) : description;
1624:            }
1625:
1626:            //-----------------------------------------------------------------------
1627:            // boilerplate
1628:            //-----------------------------------------------------------------------
1629:
1630:            /**
1631:             * Tests two NumeratorSubstitutions for equality
1632:             * @param that The other NumeratorSubstitution
1633:             * @return true if the two objects are functionally equivalent
1634:             */
1635:            public boolean equals(Object that) {
1636:                if (super .equals(that)) {
1637:                    NumeratorSubstitution that2 = (NumeratorSubstitution) that;
1638:                    return denominator == that2.denominator;
1639:                } else {
1640:                    return false;
1641:                }
1642:            }
1643:
1644:            //-----------------------------------------------------------------------
1645:            // formatting
1646:            //-----------------------------------------------------------------------
1647:
1648:            /**
1649:             * Performs a mathematical operation on the number, formats it using
1650:             * either ruleSet or decimalFormat, and inserts the result into
1651:             * toInsertInto.
1652:             * @param number The number being formatted.
1653:             * @param toInsertInto The string we insert the result into
1654:             * @param pos The position in toInsertInto where the owning rule's
1655:             * rule text begins (this value is added to this substitution's
1656:             * position to determine exactly where to insert the new text)
1657:             */
1658:            public void doSubstitution(double number,
1659:                    StringBuffer toInsertInto, int pos) {
1660:                // perform a transformation on the number being formatted that
1661:                // is dependent on the type of substitution this is
1662:                String s = toInsertInto.toString();
1663:                double numberToFormat = transformNumber(number);
1664:
1665:                if (withZeros && ruleSet != null) {
1666:                    // if there are leading zeros in the decimal expansion then emit them
1667:                    long nf = (long) numberToFormat;
1668:                    int len = toInsertInto.length();
1669:                    while ((nf *= 10) < denominator) {
1670:                        toInsertInto.insert(pos + this .pos, ' ');
1671:                        ruleSet.format(0, toInsertInto, pos + this .pos);
1672:                    }
1673:                    pos += toInsertInto.length() - len;
1674:                }
1675:
1676:                // if the result is an integer, from here on out we work in integer
1677:                // space (saving time and memory and preserving accuracy)
1678:                if (numberToFormat == Math.floor(numberToFormat)
1679:                        && ruleSet != null) {
1680:                    ruleSet.format((long) numberToFormat, toInsertInto, pos
1681:                            + this .pos);
1682:
1683:                    // if the result isn't an integer, then call either our rule set's
1684:                    // format() method or our DecimalFormat's format() method to
1685:                    // format the result
1686:                } else {
1687:                    if (ruleSet != null) {
1688:                        ruleSet.format(numberToFormat, toInsertInto, pos
1689:                                + this .pos);
1690:                    } else {
1691:                        toInsertInto.insert(pos + this .pos, numberFormat
1692:                                .format(numberToFormat));
1693:                    }
1694:                }
1695:            }
1696:
1697:            /**
1698:             * Returns the number being formatted times the denominator.
1699:             * @param number The number being formatted
1700:             * @return number * denominator
1701:             */
1702:            public long transformNumber(long number) {
1703:                return Math.round(number * denominator);
1704:            }
1705:
1706:            /**
1707:             * Returns the number being formatted times the denominator.
1708:             * @param number The number being formatted
1709:             * @return number * denominator
1710:             */
1711:            public double transformNumber(double number) {
1712:                return Math.round(number * denominator);
1713:            }
1714:
1715:            //-----------------------------------------------------------------------
1716:            // parsing
1717:            //-----------------------------------------------------------------------
1718:
1719:            /**
1720:             * Dispatches to the inherited version of this function, but makes
1721:             * sure that lenientParse is off.
1722:             */
1723:            public Number doParse(String text, ParsePosition parsePosition,
1724:                    double baseValue, double upperBound, boolean lenientParse) {
1725:                // we don't have to do anything special to do the parsing here,
1726:                // but we have to turn lenient parsing off-- if we leave it on,
1727:                // it SERIOUSLY messes up the algorithm
1728:
1729:                // if withZeros is true, we need to count the zeros
1730:                // and use that to adjust the parse result
1731:                int zeroCount = 0;
1732:                if (withZeros) {
1733:                    String workText = new String(text);
1734:                    ParsePosition workPos = new ParsePosition(1);
1735:                    int digit;
1736:
1737:                    while (workText.length() > 0 && workPos.getIndex() != 0) {
1738:                        workPos.setIndex(0);
1739:                        digit = ruleSet.parse(workText, workPos, 1).intValue(); // parse zero or nothing at all
1740:                        if (workPos.getIndex() == 0) {
1741:                            // we failed, either there were no more zeros, or the number was formatted with digits
1742:                            // either way, we're done
1743:                            break;
1744:                        }
1745:
1746:                        ++zeroCount;
1747:                        parsePosition.setIndex(parsePosition.getIndex()
1748:                                + workPos.getIndex());
1749:                        workText = workText.substring(workPos.getIndex());
1750:                        while (workText.length() > 0
1751:                                && workText.charAt(0) == ' ') {
1752:                            workText = workText.substring(1);
1753:                            parsePosition
1754:                                    .setIndex(parsePosition.getIndex() + 1);
1755:                        }
1756:                    }
1757:
1758:                    text = text.substring(parsePosition.getIndex()); // arrgh!
1759:                    parsePosition.setIndex(0);
1760:                }
1761:
1762:                // we've parsed off the zeros, now let's parse the rest from our current position
1763:                Number result = super .doParse(text, parsePosition,
1764:                        withZeros ? 1 : baseValue, upperBound, false);
1765:
1766:                if (withZeros) {
1767:                    // any base value will do in this case.  is there a way to
1768:                    // force this to not bother trying all the base values?
1769:
1770:                    // compute the 'effective' base and prescale the value down
1771:                    long n = result.longValue();
1772:                    long d = 1;
1773:                    int pow = 0;
1774:                    while (d <= n) {
1775:                        d *= 10;
1776:                        ++pow;
1777:                    }
1778:                    // now add the zeros
1779:                    while (zeroCount > 0) {
1780:                        d *= 10;
1781:                        --zeroCount;
1782:                    }
1783:                    // d is now our true denominator
1784:                    result = new Double(n / (double) d);
1785:                }
1786:
1787:                return result;
1788:            }
1789:
1790:            /**
1791:             * Divides the result of parsing the substitution by the partial
1792:             * parse result.
1793:             * @param newRuleValue The result of parsing the substitution
1794:             * @param oldRuleValue The owning rule's base value
1795:             * @return newRuleValue / oldRuleValue
1796:             */
1797:            public double composeRuleValue(double newRuleValue,
1798:                    double oldRuleValue) {
1799:                return newRuleValue / oldRuleValue;
1800:            }
1801:
1802:            /**
1803:             * Sets the uper bound down to this rule's base value
1804:             * @param oldUpperBound Ignored
1805:             * @return The base value of the rule owning this substitution
1806:             */
1807:            public double calcUpperBound(double oldUpperBound) {
1808:                return denominator;
1809:            }
1810:
1811:            //-----------------------------------------------------------------------
1812:            // simple accessor
1813:            //-----------------------------------------------------------------------
1814:
1815:            /**
1816:             * The token character for a NumeratorSubstitution is &lt;
1817:             * @return '&lt;'
1818:             */
1819:            char tokenChar() {
1820:                return '<';
1821:            }
1822:        }
1823:
1824:        //===================================================================
1825:        // NullSubstitution
1826:        //===================================================================
1827:
1828:        /**
1829:         * A substitution which does nothing.  This class exists just to simplify
1830:         * the logic in some other routines so that they don't have to worry
1831:         * about how many substitutions a rule has.
1832:         */
1833:        class NullSubstitution extends NFSubstitution {
1834:            //-----------------------------------------------------------------------
1835:            // constants
1836:            //-----------------------------------------------------------------------
1837:
1838:            /**
1839:             * Puts a copyright in the .class file
1840:             */
1841:            private static final String copyrightNotice = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
1842:
1843:            //-----------------------------------------------------------------------
1844:            // construction
1845:            //-----------------------------------------------------------------------
1846:
1847:            /**
1848:             * Constructs a NullSubstitution.  This just delegates to the superclass
1849:             * constructor, but the only value we really care about is the position.
1850:             */
1851:            NullSubstitution(int pos, NFRuleSet ruleSet,
1852:                    RuleBasedNumberFormat formatter, String description) {
1853:                super (pos, ruleSet, formatter, description);
1854:            }
1855:
1856:            //-----------------------------------------------------------------------
1857:            // boilerplate
1858:            //-----------------------------------------------------------------------
1859:
1860:            /**
1861:             * Only checks for class equality
1862:             */
1863:            public boolean equals(Object that) {
1864:                return super .equals(that);
1865:            }
1866:
1867:            /**
1868:             * NullSubstitutions don't show up in the textual representation
1869:             * of a RuleBasedNumberFormat
1870:             */
1871:            public String toString() {
1872:                return "";
1873:            }
1874:
1875:            //-----------------------------------------------------------------------
1876:            // formatting
1877:            //-----------------------------------------------------------------------
1878:
1879:            /**
1880:             * Does nothing.
1881:             */
1882:            public void doSubstitution(long number, StringBuffer toInsertInto,
1883:                    int pos) {
1884:            }
1885:
1886:            /**
1887:             * Does nothing.
1888:             */
1889:            public void doSubstitution(double number,
1890:                    StringBuffer toInsertInto, int pos) {
1891:            }
1892:
1893:            /**
1894:             * Never called.
1895:             */
1896:            ///CLOVER:OFF
1897:            public long transformNumber(long number) {
1898:                return 0;
1899:            }
1900:
1901:            ///CLOVER:ON
1902:
1903:            /**
1904:             * Never called.
1905:             */
1906:            ///CLOVER:OFF
1907:            public double transformNumber(double number) {
1908:                return 0;
1909:            }
1910:
1911:            ///CLOVER:ON
1912:
1913:            //-----------------------------------------------------------------------
1914:            // parsing
1915:            //-----------------------------------------------------------------------
1916:
1917:            /**
1918:             * Returns the partial parse result unchanged
1919:             */
1920:            public Number doParse(String text, ParsePosition parsePosition,
1921:                    double baseValue, double upperBound, boolean lenientParse) {
1922:                if (baseValue == (long) baseValue) {
1923:                    return new Long((long) baseValue);
1924:                } else {
1925:                    return new Double(baseValue);
1926:                }
1927:            }
1928:
1929:            /**
1930:             * Never called.
1931:             */
1932:            ///CLOVER:OFF
1933:            public double composeRuleValue(double newRuleValue,
1934:                    double oldRuleValue) {
1935:                return 0;
1936:            }
1937:
1938:            ///CLOVER:ON
1939:
1940:            /**
1941:             * Never called.
1942:             */
1943:            ///CLOVER:OFF
1944:            public double calcUpperBound(double oldUpperBound) {
1945:                return 0;
1946:            }
1947:
1948:            ///CLOVER:ON
1949:
1950:            //-----------------------------------------------------------------------
1951:            // simple accessors
1952:            //-----------------------------------------------------------------------
1953:
1954:            /**
1955:             * Returns true (this _is_ a NullSubstitution).
1956:             * @return true
1957:             */
1958:            public boolean isNullSubstitution() {
1959:                return true;
1960:            }
1961:
1962:            /**
1963:             * Never called.
1964:             */
1965:            ///CLOVER:OFF
1966:            char tokenChar() {
1967:                return ' ';
1968:            }
1969:            ///CLOVER:ON
1970:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.