6827009: Project Coin: Strings in Switch jdk7-b76

Mon, 02 Nov 2009 21:36:59 -0800

author
darcy
date
Mon, 02 Nov 2009 21:36:59 -0800
changeset 430
8fb9b4be3cb1
parent 429
c8083dc525b6
child 431
4c8c6159159c
child 433
82f6e78efcf5

6827009: Project Coin: Strings in Switch
Reviewed-by: jjg, mcimadamore

src/share/classes/com/sun/tools/javac/code/Source.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Lower.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/resources/compiler.properties file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/BadlyTypedLabel1.java file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/BadlyTypedLabel1.out file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/BadlyTypedLabel2.java file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/BadlyTypedLabel2.out file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/NonConstantLabel.java file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/NonConstantLabel.out file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/OneCaseSwitches.java file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/RSCL1.out file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/RSCL2.out file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/RepeatedStringCaseLabels1.java file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/RepeatedStringCaseLabels2.java file | annotate | diff | comparison | revisions
test/tools/javac/StringsInSwitch/StringSwitches.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Source.java	Fri Oct 30 10:55:00 2009 -0700
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Source.java	Mon Nov 02 21:36:59 2009 -0800
     1.3 @@ -110,6 +110,9 @@
     1.4      }
     1.5  
     1.6      /** Allow encoding errors, giving only warnings. */
     1.7 +    public boolean allowStringsInSwitch() {
     1.8 +        return compareTo(JDK1_7) >= 0;
     1.9 +    }
    1.10      public boolean allowEncodingErrors() {
    1.11          return compareTo(JDK1_6) < 0;
    1.12      }
     2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Oct 30 10:55:00 2009 -0700
     2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Nov 02 21:36:59 2009 -0800
     2.3 @@ -115,6 +115,8 @@
     2.4          allowBoxing = source.allowBoxing();
     2.5          allowCovariantReturns = source.allowCovariantReturns();
     2.6          allowAnonOuterThis = source.allowAnonOuterThis();
     2.7 +        allowStringsInSwitch = source.allowStringsInSwitch();
     2.8 +        sourceName = source.name;
     2.9          relax = (options.get("-retrofit") != null ||
    2.10                   options.get("-relax") != null);
    2.11          useBeforeDeclarationWarning = options.get("useBeforeDeclarationWarning") != null;
    2.12 @@ -167,6 +169,16 @@
    2.13       */
    2.14      boolean enableSunApiLintControl;
    2.15  
    2.16 +    /**
    2.17 +     * Switch: allow strings in switch?
    2.18 +     */
    2.19 +    boolean allowStringsInSwitch;
    2.20 +
    2.21 +    /**
    2.22 +     * Switch: name of source level; used for error reporting.
    2.23 +     */
    2.24 +    String sourceName;
    2.25 +
    2.26      /** Check kind and type of given tree against protokind and prototype.
    2.27       *  If check succeeds, store type in tree and return it.
    2.28       *  If check fails, store errType in tree and return it.
    2.29 @@ -886,7 +898,15 @@
    2.30          boolean enumSwitch =
    2.31              allowEnums &&
    2.32              (seltype.tsym.flags() & Flags.ENUM) != 0;
    2.33 -        if (!enumSwitch)
    2.34 +        boolean stringSwitch = false;
    2.35 +        if (types.isSameType(seltype, syms.stringType)) {
    2.36 +            if (allowStringsInSwitch) {
    2.37 +                stringSwitch = true;
    2.38 +            } else {
    2.39 +                log.error(tree.selector.pos(), "string.switch.not.supported.in.source", sourceName);
    2.40 +            }
    2.41 +        }
    2.42 +        if (!enumSwitch && !stringSwitch)
    2.43              seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
    2.44  
    2.45          // Attribute all cases and
    2.46 @@ -909,7 +929,8 @@
    2.47                      Type pattype = attribExpr(c.pat, switchEnv, seltype);
    2.48                      if (pattype.tag != ERROR) {
    2.49                          if (pattype.constValue() == null) {
    2.50 -                            log.error(c.pat.pos(), "const.expr.req");
    2.51 +                            log.error(c.pat.pos(),
    2.52 +                                      (stringSwitch ? "string.const.req" : "const.expr.req"));
    2.53                          } else if (labels.contains(pattype.constValue())) {
    2.54                              log.error(c.pos(), "duplicate.case.label");
    2.55                          } else {
     3.1 --- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Oct 30 10:55:00 2009 -0700
     3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Mon Nov 02 21:36:59 2009 -0800
     3.3 @@ -357,7 +357,7 @@
     3.4       *          case 2: stmt2
     3.5       *          }
     3.6       *  </pre>
     3.7 -     *  with the auxilliary table intialized as follows:
     3.8 +     *  with the auxiliary table initialized as follows:
     3.9       *  <pre>
    3.10       *          class Outer$0 {
    3.11       *              synthetic final int[] $EnumMap$Color = new int[Color.values().length];
    3.12 @@ -858,7 +858,7 @@
    3.13          int acode;                // The access code of the access method.
    3.14          List<Type> argtypes;      // The argument types of the access method.
    3.15          Type restype;             // The result type of the access method.
    3.16 -        List<Type> thrown;        // The thrown execeptions of the access method.
    3.17 +        List<Type> thrown;        // The thrown exceptions of the access method.
    3.18          switch (vsym.kind) {
    3.19          case VAR:
    3.20              acode = accessCode(tree, enclOp);
    3.21 @@ -2463,7 +2463,7 @@
    3.22      // the dead code, which will not be eliminated during code generation.
    3.23      // Note that Flow.isFalse and Flow.isTrue only return true
    3.24      // for constant expressions in the sense of JLS 15.27, which
    3.25 -    // are guaranteed to have no side-effects.  More agressive
    3.26 +    // are guaranteed to have no side-effects.  More aggressive
    3.27      // constant propagation would require that we take care to
    3.28      // preserve possible side-effects in the condition expression.
    3.29  
    3.30 @@ -2850,7 +2850,7 @@
    3.31  
    3.32          // If translated left hand side is an Apply, we are
    3.33          // seeing an access method invocation. In this case, return
    3.34 -        // that access method invokation as result.
    3.35 +        // that access method invocation as result.
    3.36          if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
    3.37              result = tree.arg;
    3.38          } else {
    3.39 @@ -2900,7 +2900,7 @@
    3.40      }
    3.41          // where
    3.42          /**
    3.43 -         * A statment of the form
    3.44 +         * A statement of the form
    3.45           *
    3.46           * <pre>
    3.47           *     for ( T v : arrayexpr ) stmt;
    3.48 @@ -3109,12 +3109,17 @@
    3.49          Type selsuper = types.supertype(tree.selector.type);
    3.50          boolean enumSwitch = selsuper != null &&
    3.51              (tree.selector.type.tsym.flags() & ENUM) != 0;
    3.52 -        Type target = enumSwitch ? tree.selector.type : syms.intType;
    3.53 +        boolean stringSwitch = selsuper != null &&
    3.54 +            types.isSameType(tree.selector.type, syms.stringType);
    3.55 +        Type target = enumSwitch ? tree.selector.type :
    3.56 +            (stringSwitch? syms.stringType : syms.intType);
    3.57          tree.selector = translate(tree.selector, target);
    3.58          tree.cases = translateCases(tree.cases);
    3.59          if (enumSwitch) {
    3.60              result = visitEnumSwitch(tree);
    3.61              patchTargets(result, tree, result);
    3.62 +        } else if (stringSwitch) {
    3.63 +            result = visitStringSwitch(tree);
    3.64          } else {
    3.65              result = tree;
    3.66          }
    3.67 @@ -3144,6 +3149,184 @@
    3.68          return make.Switch(selector, cases.toList());
    3.69      }
    3.70  
    3.71 +    public JCTree visitStringSwitch(JCSwitch tree) {
    3.72 +        List<JCCase> caseList = tree.getCases();
    3.73 +        int alternatives = caseList.size();
    3.74 +
    3.75 +        if (alternatives == 0) { // Strange but legal possibility
    3.76 +            return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
    3.77 +        } else {
    3.78 +            /*
    3.79 +             * The general approach used is to translate a single
    3.80 +             * string switch statement into a series of two chained
    3.81 +             * switch statements: the first a synthesized statement
    3.82 +             * switching on the argument string's hash value and
    3.83 +             * computing a string's position in the list of original
    3.84 +             * case labels, if any, followed by a second switch on the
    3.85 +             * computed integer value.  The second switch has the same
    3.86 +             * code structure as the original string switch statement
    3.87 +             * except that the string case labels are replaced with
    3.88 +             * positional integer constants starting at 0.
    3.89 +             *
    3.90 +             * The first switch statement can be thought of as an
    3.91 +             * inlined map from strings to their position in the case
    3.92 +             * label list.  An alternate implementation would use an
    3.93 +             * actual Map for this purpose, as done for enum switches.
    3.94 +             *
    3.95 +             * With some additional effort, it would be possible to
    3.96 +             * use a single switch statement on the hash code of the
    3.97 +             * argument, but care would need to be taken to preserve
    3.98 +             * the proper control flow in the presence of hash
    3.99 +             * collisions and other complications, such as
   3.100 +             * fallthroughs.  Switch statements with one or two
   3.101 +             * alternatives could also be specially translated into
   3.102 +             * if-then statements to omit the computation of the hash
   3.103 +             * code.
   3.104 +             *
   3.105 +             * The generated code assumes that the hashing algorithm
   3.106 +             * of String is the same in the compilation environment as
   3.107 +             * in the environment the code will run in.  The string
   3.108 +             * hashing algorithm in the SE JDK has been unchanged
   3.109 +             * since at least JDK 1.2.
   3.110 +             */
   3.111 +
   3.112 +            ListBuffer<JCStatement> stmtList = new ListBuffer<JCStatement>();
   3.113 +
   3.114 +            // Map from String case labels to their original position in
   3.115 +            // the list of case labels.
   3.116 +            Map<String, Integer> caseLabelToPosition =
   3.117 +                new LinkedHashMap<String, Integer>(alternatives + 1, 1.0f);
   3.118 +
   3.119 +            // Map of hash codes to the string case labels having that hashCode.
   3.120 +            Map<Integer, Set<String>> hashToString =
   3.121 +                new LinkedHashMap<Integer, Set<String>>(alternatives + 1, 1.0f);
   3.122 +
   3.123 +            int casePosition = 0;
   3.124 +            for(JCCase oneCase : caseList) {
   3.125 +                JCExpression expression = oneCase.getExpression();
   3.126 +
   3.127 +                if (expression != null) { // expression for a "default" case is null
   3.128 +                    String labelExpr = (String) expression.type.constValue();
   3.129 +                    Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
   3.130 +                    assert mapping == null;
   3.131 +                    int hashCode = labelExpr.hashCode();
   3.132 +
   3.133 +                    Set<String> stringSet = hashToString.get(hashCode);
   3.134 +                    if (stringSet == null) {
   3.135 +                        stringSet = new LinkedHashSet<String>(1, 1.0f);
   3.136 +                        stringSet.add(labelExpr);
   3.137 +                        hashToString.put(hashCode, stringSet);
   3.138 +                    } else {
   3.139 +                        boolean added = stringSet.add(labelExpr);
   3.140 +                        assert added;
   3.141 +                    }
   3.142 +                }
   3.143 +                casePosition++;
   3.144 +            }
   3.145 +
   3.146 +            // Synthesize a switch statement that has the effect of
   3.147 +            // mapping from a string to the integer position of that
   3.148 +            // string in the list of case labels.  This is done by
   3.149 +            // switching on the hashCode of the string followed by an
   3.150 +            // if-then-else chain comparing the input for equality
   3.151 +            // with all the case labels having that hash value.
   3.152 +
   3.153 +            /*
   3.154 +             * s$ = top of stack;
   3.155 +             * tmp$ = -1;
   3.156 +             * switch($s.hashCode()) {
   3.157 +             *     case caseLabel.hashCode:
   3.158 +             *         if (s$.equals("caseLabel_1")
   3.159 +             *           tmp$ = caseLabelToPosition("caseLabel_1");
   3.160 +             *         else if (s$.equals("caseLabel_2"))
   3.161 +             *           tmp$ = caseLabelToPosition("caseLabel_2");
   3.162 +             *         ...
   3.163 +             *         break;
   3.164 +             * ...
   3.165 +             * }
   3.166 +             */
   3.167 +
   3.168 +            VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
   3.169 +                                               names.fromString("s" + tree.pos + target.syntheticNameChar()),
   3.170 +                                               syms.stringType,
   3.171 +                                               currentMethodSym);
   3.172 +            stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
   3.173 +
   3.174 +            VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
   3.175 +                                                 names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
   3.176 +                                                 syms.intType,
   3.177 +                                                 currentMethodSym);
   3.178 +            JCVariableDecl dollar_tmp_def =
   3.179 +                (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
   3.180 +            dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
   3.181 +            stmtList.append(dollar_tmp_def);
   3.182 +            ListBuffer<JCCase> caseBuffer = ListBuffer.lb();
   3.183 +            // hashCode will trigger nullcheck on original switch expression
   3.184 +            JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
   3.185 +                                                       names.hashCode,
   3.186 +                                                       List.<JCExpression>nil()).setType(syms.intType);
   3.187 +            JCSwitch switch1 = make.Switch(hashCodeCall,
   3.188 +                                        caseBuffer.toList());
   3.189 +            for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
   3.190 +                int hashCode = entry.getKey();
   3.191 +                Set<String> stringsWithHashCode = entry.getValue();
   3.192 +                assert stringsWithHashCode.size() >= 1;
   3.193 +
   3.194 +                JCStatement elsepart = null;
   3.195 +                for(String caseLabel : stringsWithHashCode ) {
   3.196 +                    JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
   3.197 +                                                                   names.equals,
   3.198 +                                                                   List.<JCExpression>of(make.Literal(caseLabel)));
   3.199 +                    elsepart = make.If(stringEqualsCall,
   3.200 +                                       make.Exec(make.Assign(make.Ident(dollar_tmp),
   3.201 +                                                             make.Literal(caseLabelToPosition.get(caseLabel))).
   3.202 +                                                 setType(dollar_tmp.type)),
   3.203 +                                       elsepart);
   3.204 +                }
   3.205 +
   3.206 +                ListBuffer<JCStatement> lb = ListBuffer.lb();
   3.207 +                JCBreak breakStmt = make.Break(null);
   3.208 +                breakStmt.target = switch1;
   3.209 +                lb.append(elsepart).append(breakStmt);
   3.210 +
   3.211 +                caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
   3.212 +            }
   3.213 +
   3.214 +            switch1.cases = caseBuffer.toList();
   3.215 +            stmtList.append(switch1);
   3.216 +
   3.217 +            // Make isomorphic switch tree replacing string labels
   3.218 +            // with corresponding integer ones from the label to
   3.219 +            // position map.
   3.220 +
   3.221 +            ListBuffer<JCCase> lb = ListBuffer.lb();
   3.222 +            JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
   3.223 +            for(JCCase oneCase : caseList ) {
   3.224 +                // Rewire up old unlabeled break statements to the
   3.225 +                // replacement switch being created.
   3.226 +                patchTargets(oneCase, tree, switch2);
   3.227 +
   3.228 +                boolean isDefault = (oneCase.getExpression() == null);
   3.229 +                JCExpression caseExpr;
   3.230 +                if (isDefault)
   3.231 +                    caseExpr = null;
   3.232 +                else {
   3.233 +                    caseExpr = make.Literal(caseLabelToPosition.get((String)oneCase.
   3.234 +                                                                    getExpression().
   3.235 +                                                                    type.constValue()));
   3.236 +                }
   3.237 +
   3.238 +                lb.append(make.Case(caseExpr,
   3.239 +                                    oneCase.getStatements()));
   3.240 +            }
   3.241 +
   3.242 +            switch2.cases = lb.toList();
   3.243 +            stmtList.append(switch2);
   3.244 +
   3.245 +            return make.Block(0L, stmtList.toList());
   3.246 +        }
   3.247 +    }
   3.248 +
   3.249      public void visitNewArray(JCNewArray tree) {
   3.250          tree.elemtype = translate(tree.elemtype);
   3.251          for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
     4.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Oct 30 10:55:00 2009 -0700
     4.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Nov 02 21:36:59 2009 -0800
     4.3 @@ -433,6 +433,8 @@
     4.4      Internal error: stack sim error on {0}
     4.5  compiler.err.static.imp.only.classes.and.interfaces=\
     4.6      static import only from classes and interfaces
     4.7 +compiler.err.string.const.req=\
     4.8 +    constant string expression required
     4.9  compiler.err.synthetic.name.conflict=\
    4.10      the symbol {0} conflicts with a compiler-synthesized symbol in {1}
    4.11  compiler.warn.synthetic.name.conflict=\
    4.12 @@ -1226,6 +1228,10 @@
    4.13      diamond operator is not supported in -source {0}\n\
    4.14  (use -source 7 or higher to enable diamond operator)
    4.15  
    4.16 +compiler.err.string.switch.not.supported.in.source=\
    4.17 +    strings in switch are not supported in -source {0}\n\
    4.18 +(use -source 7 or higher to enable strings in switch)
    4.19 +
    4.20  ########################################
    4.21  # Diagnostics for where clause implementation
    4.22  # used by the RichDiagnosticFormatter.
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/tools/javac/StringsInSwitch/BadlyTypedLabel1.java	Mon Nov 02 21:36:59 2009 -0800
     5.3 @@ -0,0 +1,17 @@
     5.4 +/*
     5.5 + * @test  /nodynamiccopyright/
     5.6 + * @bug 6827009
     5.7 + * @summary Check for case labels of different types.
     5.8 + * @compile/fail -source 6 BadlyTypedLabel1.java
     5.9 + * @compile/fail/ref=BadlyTypedLabel1.out -XDstdout -XDrawDiagnostics BadlyTypedLabel1.java
    5.10 + */
    5.11 +class BadlyTypedLabel1 {
    5.12 +    String m(String s) {
    5.13 +        switch(s) {
    5.14 +        case "Hello World":
    5.15 +            return(s);
    5.16 +        case 42:
    5.17 +            return ("Don't forget your towel!");
    5.18 +        }
    5.19 +    }
    5.20 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/test/tools/javac/StringsInSwitch/BadlyTypedLabel1.out	Mon Nov 02 21:36:59 2009 -0800
     6.3 @@ -0,0 +1,2 @@
     6.4 +BadlyTypedLabel1.java:13:14: compiler.err.prob.found.req: (compiler.misc.incompatible.types), int, java.lang.String
     6.5 +1 error
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/test/tools/javac/StringsInSwitch/BadlyTypedLabel2.java	Mon Nov 02 21:36:59 2009 -0800
     7.3 @@ -0,0 +1,19 @@
     7.4 +/*
     7.5 + * @test  /nodynamiccopyright/
     7.6 + * @bug 6827009
     7.7 + * @summary Check for case lables of different types.
     7.8 + * @compile/fail -source 6 BadlyTypedLabel2.java
     7.9 + * @compile/fail/ref=BadlyTypedLabel2.out -XDstdout -XDrawDiagnostics BadlyTypedLabel2.java
    7.10 + */
    7.11 +import static java.math.RoundingMode.*;
    7.12 +
    7.13 +class BadlyTypedLabel2 {
    7.14 +    String m(String s) {
    7.15 +        switch(s) {
    7.16 +        case "Oh what a feeling...":
    7.17 +            return(s);
    7.18 +        case CEILING:
    7.19 +            return ("... switching on the ceiling!");
    7.20 +        }
    7.21 +    }
    7.22 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/test/tools/javac/StringsInSwitch/BadlyTypedLabel2.out	Mon Nov 02 21:36:59 2009 -0800
     8.3 @@ -0,0 +1,2 @@
     8.4 +BadlyTypedLabel2.java:15:14: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.math.RoundingMode, java.lang.String
     8.5 +1 error
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/test/tools/javac/StringsInSwitch/NonConstantLabel.java	Mon Nov 02 21:36:59 2009 -0800
     9.3 @@ -0,0 +1,18 @@
     9.4 +/*
     9.5 + * @test  /nodynamiccopyright/
     9.6 + * @bug 6827009
     9.7 + * @summary Check for non-constant case labels.
     9.8 + * @compile/fail -source 6 NonConstantLabel.java
     9.9 + * @compile/fail/ref=NonConstantLabel.out -XDstdout -XDrawDiagnostics NonConstantLabel.java
    9.10 + */
    9.11 +class NonConstantLabel {
    9.12 +    String m(String s) {
    9.13 +        String fauxConstant = "Goodbye Cruel World";
    9.14 +        switch(s) {
    9.15 +        case "Hello World":
    9.16 +            return(s);
    9.17 +        case fauxConstant:
    9.18 +            return (s + s);
    9.19 +        }
    9.20 +    }
    9.21 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/test/tools/javac/StringsInSwitch/NonConstantLabel.out	Mon Nov 02 21:36:59 2009 -0800
    10.3 @@ -0,0 +1,2 @@
    10.4 +NonConstantLabel.java:14:14: compiler.err.string.const.req
    10.5 +1 error
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/test/tools/javac/StringsInSwitch/OneCaseSwitches.java	Mon Nov 02 21:36:59 2009 -0800
    11.3 @@ -0,0 +1,303 @@
    11.4 +/*
    11.5 + * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
    11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    11.7 + *
    11.8 + * This code is free software; you can redistribute it and/or modify it
    11.9 + * under the terms of the GNU General Public License version 2 only, as
   11.10 + * published by the Free Software Foundation.
   11.11 + *
   11.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   11.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   11.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   11.15 + * version 2 for more details (a copy is included in the LICENSE file that
   11.16 + * accompanied this code).
   11.17 + *
   11.18 + * You should have received a copy of the GNU General Public License version
   11.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   11.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   11.21 + *
   11.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   11.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
   11.24 + * have any questions.
   11.25 + */
   11.26 +
   11.27 +/*
   11.28 + * @test
   11.29 + * @bug 6827009
   11.30 + * @summary Positive tests for strings in switch with few alternatives.
   11.31 + * @compile/fail -source 6 OneCaseSwitches.java
   11.32 + * @compile                OneCaseSwitches.java
   11.33 + * @run main OneCaseSwitches
   11.34 + * @author  Joseph D. Darcy
   11.35 + */
   11.36 +
   11.37 +import java.lang.reflect.*;
   11.38 +import java.lang.annotation.*;
   11.39 +import java.util.*;
   11.40 +import static java.lang.annotation.RetentionPolicy.*;
   11.41 +
   11.42 +public class OneCaseSwitches {
   11.43 +    @Retention(RUNTIME)
   11.44 +    @interface TestMeForNull {}
   11.45 +
   11.46 +    @TestMeForNull
   11.47 +    public static int zeroCasesNoDefault(String s, Set<String> stringSet, boolean expected) {
   11.48 +        int failures = 0;
   11.49 +        switch(s) {
   11.50 +        }
   11.51 +        return failures;
   11.52 +    }
   11.53 +
   11.54 +    @TestMeForNull
   11.55 +    public static int zeroCasesWithDefault(String s, Set<String> stringSet, boolean expected) {
   11.56 +        int failures = 2;
   11.57 +        boolean addResult;
   11.58 +
   11.59 +        switch(s) {
   11.60 +        default:
   11.61 +            failures = 0;
   11.62 +            addResult = stringSet.add(s);
   11.63 +            if (addResult != expected) {
   11.64 +                failures++;
   11.65 +                System.err.println("zeroCaseWithDefault: Expectedly got add result of " + addResult +
   11.66 +                                   " on string " + s);
   11.67 +            }
   11.68 +        }
   11.69 +
   11.70 +        return failures;
   11.71 +    }
   11.72 +
   11.73 +    @TestMeForNull
   11.74 +    public static int zeroCasesWithDefaultBreak(String s, Set<String> stringSet, boolean expected) {
   11.75 +        int failures = 2;
   11.76 +        boolean addResult;
   11.77 +
   11.78 +        switch(s) {
   11.79 +        default:
   11.80 +            failures = zeroCasesWithDefault(s, stringSet, expected);
   11.81 +            break;
   11.82 +        }
   11.83 +
   11.84 +        return failures;
   11.85 +    }
   11.86 +
   11.87 +    @TestMeForNull
   11.88 +    public static int oneCaseNoDefault(String s, Set<String> stringSet, boolean expected) {
   11.89 +        int failures = 2;
   11.90 +        boolean addResult;
   11.91 +
   11.92 +        switch(s) {
   11.93 +        case "foo":
   11.94 +            failures = 0;
   11.95 +            addResult = stringSet.add(s);
   11.96 +            if (addResult != expected) {
   11.97 +                failures++;
   11.98 +                System.err.println("oneCaseNoDefault: Unexpectedly got add result of " + addResult +
   11.99 +                                   " on string " + s);
  11.100 +            }
  11.101 +        }
  11.102 +
  11.103 +        return failures;
  11.104 +    }
  11.105 +
  11.106 +    @TestMeForNull
  11.107 +    public static int oneCaseNoDefaultBreak(String s, Set<String> stringSet, boolean expected) {
  11.108 +        int failures = 2;
  11.109 +        boolean addResult;
  11.110 +
  11.111 +        switch(s) {
  11.112 +        case "foo":
  11.113 +            failures = oneCaseNoDefaultBreak(s, stringSet, expected);
  11.114 +            break;
  11.115 +        }
  11.116 +
  11.117 +        return failures;
  11.118 +    }
  11.119 +
  11.120 +    @TestMeForNull
  11.121 +    public static int oneCaseWithDefault(String s, Set<String> stringSet, boolean expected) {
  11.122 +        int failures = 2;
  11.123 +        boolean addResult;;
  11.124 +
  11.125 +        switch(s) {
  11.126 +        case "foo":
  11.127 +            failures = 0;
  11.128 +            addResult = stringSet.add(s);
  11.129 +            if (addResult != expected) {
  11.130 +                failures++;
  11.131 +                System.err.println("oneCaseNoDefault: Expectedly got add result of " + addResult +
  11.132 +                                   " on string " + s);
  11.133 +            }
  11.134 +            break;
  11.135 +        default:
  11.136 +            break;
  11.137 +        }
  11.138 +
  11.139 +        return failures;
  11.140 +    }
  11.141 +
  11.142 +    @TestMeForNull
  11.143 +    public static int oneCaseBreakOnly(String s, Set<String> stringSet, boolean expected) {
  11.144 +        int failures = 1;
  11.145 +        switch(s) {
  11.146 +        case "foo":
  11.147 +            break;
  11.148 +        }
  11.149 +        failures = 0;
  11.150 +        return failures;
  11.151 +    }
  11.152 +
  11.153 +    @TestMeForNull
  11.154 +    public static int oneCaseDefaultBreakOnly(String s, Set<String> stringSet, boolean expected) {
  11.155 +        int failures = 1;
  11.156 +        switch(s) {
  11.157 +        default:
  11.158 +            break;
  11.159 +        }
  11.160 +        failures = 0;
  11.161 +        return failures;
  11.162 +    }
  11.163 +
  11.164 +
  11.165 +    static int testNullBehavior() {
  11.166 +        int failures = 0;
  11.167 +        int count = 0;
  11.168 +
  11.169 +        Method[] methods = OneCaseSwitches.class.getDeclaredMethods();
  11.170 +
  11.171 +        try {
  11.172 +            for(Method method : methods) {
  11.173 +                count++;
  11.174 +                try {
  11.175 +                    if (method.isAnnotationPresent(TestMeForNull.class)) {
  11.176 +                        System.out.println("Testing method " + method);
  11.177 +                        method.invoke(null, (String)null, emptyStringSet, false);
  11.178 +                        failures++;
  11.179 +                        System.err.println("Didn't get NPE as expected from " + method);
  11.180 +                    }
  11.181 +                } catch (InvocationTargetException ite) { // Expected
  11.182 +                    Throwable targetException = ite.getTargetException();
  11.183 +                    if (! (targetException instanceof NullPointerException)) {
  11.184 +                        failures++; // Wrong exception thrown
  11.185 +                        System.err.println("Didn't get expected target exception NPE, got " +
  11.186 +                                           ite.getClass().getName());
  11.187 +                    }
  11.188 +                }
  11.189 +            }
  11.190 +        } catch (Exception e) {
  11.191 +            throw new RuntimeException(e);
  11.192 +        }
  11.193 +
  11.194 +        if (count == 0) {
  11.195 +            failures++;
  11.196 +            System.err.println("Did not find any annotated methods.");
  11.197 +        }
  11.198 +        return failures;
  11.199 +    }
  11.200 +
  11.201 +    static int testZeroCases() {
  11.202 +        int failures = 0;
  11.203 +        Set<String> noDefaultSet = new HashSet<String>();
  11.204 +        Set<String> defaultSet   = new HashSet<String>();
  11.205 +
  11.206 +        zeroCasesNoDefault(FOO, noDefaultSet, false);
  11.207 +        for(String word : words) {
  11.208 +            zeroCasesNoDefault(word, noDefaultSet, false);
  11.209 +        }
  11.210 +
  11.211 +        if (!noDefaultSet.isEmpty()) {
  11.212 +            failures++;
  11.213 +            System.err.println("Non-empty set after zeroCasesNoDefault");
  11.214 +        }
  11.215 +
  11.216 +        for(String word : words) {
  11.217 +            zeroCasesWithDefault(word, defaultSet, true);
  11.218 +        }
  11.219 +        if (defaultSet.size() != words.length) {
  11.220 +            failures++;
  11.221 +            System.err.println("Missing strings after zeroCasesWithDefault");
  11.222 +        }
  11.223 +
  11.224 +        return failures;
  11.225 +    }
  11.226 +
  11.227 +    static int testOneCaseNoDefault() {
  11.228 +        int failures = 0;
  11.229 +        Set<String> s = new HashSet<String>();
  11.230 +        s.add("foo");
  11.231 +        Set<String> fooSet = Collections.unmodifiableSet(s);
  11.232 +        Set<String> testSet   = new HashSet<String>();
  11.233 +
  11.234 +        oneCaseNoDefault(FOO, testSet, true);
  11.235 +        if (!testSet.equals(fooSet)) {
  11.236 +            failures++;
  11.237 +            System.err.println("Unexpected result from oneCaseNoDefault: didn't get {\"Foo\"}");
  11.238 +        }
  11.239 +
  11.240 +        for(String word : words) {
  11.241 +            oneCaseNoDefault(word, testSet, false);
  11.242 +        }
  11.243 +        if (!testSet.equals(fooSet)) {
  11.244 +            failures++;
  11.245 +            System.err.println("Unexpected result from oneCaseNoDefault: didn't get {\"Foo\"}");
  11.246 +        }
  11.247 +
  11.248 +        return failures;
  11.249 +    }
  11.250 +
  11.251 +    static int testBreakOnly() {
  11.252 +        int failures = 0;
  11.253 +
  11.254 +        for(String word : words) {
  11.255 +            failures += oneCaseBreakOnly(word, emptyStringSet, true);
  11.256 +            failures += oneCaseDefaultBreakOnly(word, emptyStringSet, true);
  11.257 +        }
  11.258 +
  11.259 +        return failures;
  11.260 +    }
  11.261 +
  11.262 +    static int testExpressionEval() {
  11.263 +        String s = "a";
  11.264 +        int errors = 2;
  11.265 +
  11.266 +        System.out.println("Testing expression evaluation.");
  11.267 +
  11.268 +        switch (s + s) {
  11.269 +        case "aa":
  11.270 +            errors = 0;
  11.271 +            break;
  11.272 +
  11.273 +        case "aaaa":
  11.274 +            errors = 1;
  11.275 +            System.err.println("Suspected bad expression evaluation.");
  11.276 +            break;
  11.277 +
  11.278 +        default:
  11.279 +             throw new RuntimeException("Should not reach here.");
  11.280 +        }
  11.281 +        return errors;
  11.282 +    }
  11.283 +
  11.284 +    static final String FOO = "foo";
  11.285 +
  11.286 +    static final String[] words = {"baz",
  11.287 +                                   "quux",
  11.288 +                                   "wombat",
  11.289 +                                   "\u0ccc\u0012"}; // hash collision with "foo"
  11.290 +
  11.291 +    final static Set<String> emptyStringSet = Collections.emptySet();
  11.292 +
  11.293 +    public static void main(String... args) {
  11.294 +        int failures = 0;
  11.295 +
  11.296 +        failures += testNullBehavior();
  11.297 +        failures += testZeroCases();
  11.298 +        failures += testOneCaseNoDefault();
  11.299 +        failures += testBreakOnly();
  11.300 +        failures += testExpressionEval();
  11.301 +
  11.302 +        if (failures > 0) {
  11.303 +            throw new RuntimeException();
  11.304 +        }
  11.305 +    }
  11.306 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/test/tools/javac/StringsInSwitch/RSCL1.out	Mon Nov 02 21:36:59 2009 -0800
    12.3 @@ -0,0 +1,2 @@
    12.4 +RepeatedStringCaseLabels1.java:13:9: compiler.err.duplicate.case.label
    12.5 +1 error
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/test/tools/javac/StringsInSwitch/RSCL2.out	Mon Nov 02 21:36:59 2009 -0800
    13.3 @@ -0,0 +1,2 @@
    13.4 +RepeatedStringCaseLabels2.java:14:9: compiler.err.duplicate.case.label
    13.5 +1 error
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/test/tools/javac/StringsInSwitch/RepeatedStringCaseLabels1.java	Mon Nov 02 21:36:59 2009 -0800
    14.3 @@ -0,0 +1,17 @@
    14.4 +/*
    14.5 + * @test  /nodynamiccopyright/
    14.6 + * @bug 6827009
    14.7 + * @summary Check for repeated string case labels.
    14.8 + * @compile/fail -source 6 RepeatedStringCaseLabels1.java
    14.9 + * @compile/fail/ref=RSCL1.out -XDstdout -XDrawDiagnostics RepeatedStringCaseLabels1.java
   14.10 + */
   14.11 +class RepeatedStringCaseLabels1 {
   14.12 +    String m(String s) {
   14.13 +        switch(s) {
   14.14 +        case "Hello World":
   14.15 +            return(s);
   14.16 +        case "Hello" + " " + "World":
   14.17 +            return (s + s);
   14.18 +        }
   14.19 +    }
   14.20 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/test/tools/javac/StringsInSwitch/RepeatedStringCaseLabels2.java	Mon Nov 02 21:36:59 2009 -0800
    15.3 @@ -0,0 +1,18 @@
    15.4 +/*
    15.5 + * @test  /nodynamiccopyright/
    15.6 + * @bug 6827009
    15.7 + * @summary Check for repeated string case labels.
    15.8 + * @compile/fail -source 6 RepeatedStringCaseLabels2.java
    15.9 + * @compile/fail/ref=RSCL2.out -XDstdout -XDrawDiagnostics RepeatedStringCaseLabels2.java
   15.10 + */
   15.11 +class RepeatedStringCaseLabels2 {
   15.12 +    String m(String s) {
   15.13 +        final String constant = "Hello" + " " + "World";
   15.14 +        switch(s) {
   15.15 +        case "Hello World":
   15.16 +            return(s);
   15.17 +        case constant:
   15.18 +            return (s + s);
   15.19 +        }
   15.20 +    }
   15.21 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/test/tools/javac/StringsInSwitch/StringSwitches.java	Mon Nov 02 21:36:59 2009 -0800
    16.3 @@ -0,0 +1,263 @@
    16.4 +/*
    16.5 + * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
    16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    16.7 + *
    16.8 + * This code is free software; you can redistribute it and/or modify it
    16.9 + * under the terms of the GNU General Public License version 2 only, as
   16.10 + * published by the Free Software Foundation.
   16.11 + *
   16.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   16.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   16.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   16.15 + * version 2 for more details (a copy is included in the LICENSE file that
   16.16 + * accompanied this code).
   16.17 + *
   16.18 + * You should have received a copy of the GNU General Public License version
   16.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   16.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   16.21 + *
   16.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   16.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
   16.24 + * have any questions.
   16.25 + */
   16.26 +
   16.27 +/*
   16.28 + * @test
   16.29 + * @bug 6827009
   16.30 + * @summary Positive tests for strings in switch.
   16.31 + * @author  Joseph D. Darcy
   16.32 + */
   16.33 +
   16.34 +public class StringSwitches {
   16.35 +
   16.36 +    public static void main(String... args) {
   16.37 +        int failures = 0;
   16.38 +
   16.39 +        failures += testPileup();
   16.40 +        failures += testSwitchingTwoWays();
   16.41 +        failures += testNamedBreak();
   16.42 +
   16.43 +        if (failures > 0) {
   16.44 +            throw new RuntimeException();
   16.45 +        }
   16.46 +    }
   16.47 +
   16.48 +    /*
   16.49 +     * A zero length string and all strings consisting only of the
   16.50 +     * zero character \u0000 have a hash code of zero.  This method
   16.51 +     * maps such strings to the number of times \u0000 appears for 0
   16.52 +     * through 6 occurrences.
   16.53 +     */
   16.54 +    private static int zeroHashes(String s) {
   16.55 +        int result = Integer.MAX_VALUE;
   16.56 +        switch(s) {
   16.57 +        case "":
   16.58 +            return 0;
   16.59 +
   16.60 +        case "\u0000":
   16.61 +            result = 1; break;
   16.62 +
   16.63 +        case "\u0000\u0000":
   16.64 +            return 2;
   16.65 +
   16.66 +        case "\u0000\u0000\u0000":
   16.67 +            result = 3; break;
   16.68 +
   16.69 +        case "\u0000\u0000\u0000\u0000":
   16.70 +            return 4;
   16.71 +
   16.72 +        case "\u0000\u0000\u0000\u0000\u0000":
   16.73 +            result = 5; break;
   16.74 +
   16.75 +        case "\u0000\u0000\u0000\u0000\u0000\u0000":
   16.76 +            return 6;
   16.77 +
   16.78 +        default:
   16.79 +            result = -1;
   16.80 +        }
   16.81 +        return result;
   16.82 +    }
   16.83 +
   16.84 +    private static int testPileup() {
   16.85 +        int failures = 0;
   16.86 +        String zero = "";
   16.87 +        for(int i = 0; i <= 6; i++, zero += "\u0000") {
   16.88 +            int result = zeroHashes(zero);
   16.89 +            if (result != i) {
   16.90 +                failures++;
   16.91 +                System.err.printf("For string \"%s\" unexpectedly got %d instead of %d%n.",
   16.92 +                                   zero, result, i);
   16.93 +            }
   16.94 +        }
   16.95 +
   16.96 +        if (zeroHashes("foo") != -1) {
   16.97 +            failures++;
   16.98 +            System.err.println("Failed to get -1 for input string.");
   16.99 +        }
  16.100 +
  16.101 +        return failures;
  16.102 +    }
  16.103 +
  16.104 +    /**
  16.105 +     * Verify that a switch on an enum and a switch with the same
  16.106 +     * structure on the string name of an enum compute equivalent
  16.107 +     * values.
  16.108 +     */
  16.109 +    private static int testSwitchingTwoWays() {
  16.110 +        int failures = 0;
  16.111 +
  16.112 +        for(MetaSynVar msv : MetaSynVar.values()) {
  16.113 +            int enumResult = enumSwitch(msv);
  16.114 +            int stringResult = stringSwitch(msv.name());
  16.115 +
  16.116 +            if (enumResult != stringResult) {
  16.117 +                failures++;
  16.118 +                System.err.printf("One value %s, computed 0x%x with the enum switch " +
  16.119 +                                  "and 0x%x with the string one.%n",
  16.120 +                                  msv, enumResult, stringResult);
  16.121 +            }
  16.122 +        }
  16.123 +
  16.124 +        return failures;
  16.125 +    }
  16.126 +
  16.127 +    private static enum MetaSynVar {
  16.128 +        FOO,
  16.129 +        BAR,
  16.130 +        BAZ,
  16.131 +        QUX,
  16.132 +        QUUX,
  16.133 +        QUUUX,
  16.134 +        MUMBLE,
  16.135 +        FOOBAR;
  16.136 +    }
  16.137 +
  16.138 +    private static int enumSwitch(MetaSynVar msv) {
  16.139 +        int result = 0;
  16.140 +        switch(msv) {
  16.141 +        case FOO:
  16.142 +            result |= (1<<0);
  16.143 +            // fallthrough:
  16.144 +
  16.145 +        case BAR:
  16.146 +        case BAZ:
  16.147 +            result |= (1<<1);
  16.148 +            break;
  16.149 +
  16.150 +        default:
  16.151 +            switch(msv) {
  16.152 +            case QUX:
  16.153 +                result |= (1<<2);
  16.154 +                break;
  16.155 +
  16.156 +            case QUUX:
  16.157 +                result |= (1<<3);
  16.158 +
  16.159 +            default:
  16.160 +                result |= (1<<4);
  16.161 +            }
  16.162 +            result |= (1<<5);
  16.163 +            break;
  16.164 +
  16.165 +        case MUMBLE:
  16.166 +            result |= (1<<6);
  16.167 +            return result;
  16.168 +
  16.169 +        case FOOBAR:
  16.170 +            result |= (1<<7);
  16.171 +            break;
  16.172 +        }
  16.173 +        result |= (1<<8);
  16.174 +        return result;
  16.175 +    }
  16.176 +
  16.177 +    private static int stringSwitch(String msvName) {
  16.178 +        int result = 0;
  16.179 +        switch(msvName) {
  16.180 +        case "FOO":
  16.181 +            result |= (1<<0);
  16.182 +            // fallthrough:
  16.183 +
  16.184 +        case "BAR":
  16.185 +        case "BAZ":
  16.186 +            result |= (1<<1);
  16.187 +            break;
  16.188 +
  16.189 +        default:
  16.190 +            switch(msvName) {
  16.191 +            case "QUX":
  16.192 +                result |= (1<<2);
  16.193 +                break;
  16.194 +
  16.195 +            case "QUUX":
  16.196 +                result |= (1<<3);
  16.197 +
  16.198 +            default:
  16.199 +                result |= (1<<4);
  16.200 +            }
  16.201 +            result |= (1<<5);
  16.202 +            break;
  16.203 +
  16.204 +        case "MUMBLE":
  16.205 +            result |= (1<<6);
  16.206 +            return result;
  16.207 +
  16.208 +        case "FOOBAR":
  16.209 +            result |= (1<<7);
  16.210 +            break;
  16.211 +        }
  16.212 +        result |= (1<<8);
  16.213 +        return result;
  16.214 +    }
  16.215 +
  16.216 +    private static int testNamedBreak() {
  16.217 +        int failures = 0;
  16.218 +        String[] testStrings  = {"a",       "b",  "c",       "d",      "e"};
  16.219 +        int[]    testExpected = { 0b101011, 0b101, 0b100001, 0b101000, 0b10000};
  16.220 +
  16.221 +        for(int i = 0; i < testStrings.length; i++) {
  16.222 +            int expected = testExpected[i];
  16.223 +            int result = namedBreak(testStrings[i]);
  16.224 +
  16.225 +            if (result != expected) {
  16.226 +                failures++;
  16.227 +
  16.228 +                System.err.printf("On input %s, got %d instead of %d.%n",
  16.229 +                                  testStrings[i], result, expected);
  16.230 +            }
  16.231 +        }
  16.232 +
  16.233 +        return failures;
  16.234 +    }
  16.235 +
  16.236 +    private static int namedBreak(String s) {
  16.237 +        int result = 0;
  16.238 +        outer: switch(s) {
  16.239 +        case "a":
  16.240 +        case "b":
  16.241 +        case "c":
  16.242 +            result |= (1<<0);
  16.243 +        inner: switch(s + s) {
  16.244 +            case "aa":
  16.245 +                result |= (1<<1);
  16.246 +                break inner;
  16.247 +
  16.248 +            case "cc":
  16.249 +                break outer;
  16.250 +
  16.251 +            default:
  16.252 +                result |= (1<<2);
  16.253 +                return result;
  16.254 +            }
  16.255 +
  16.256 +        case "d":
  16.257 +            result |= (1<<3);
  16.258 +            break outer;
  16.259 +
  16.260 +        default:
  16.261 +            return result |= (1<<4);
  16.262 +        }
  16.263 +        result |= (1<<5);
  16.264 +        return result;
  16.265 +    }
  16.266 +}

mercurial