Pesquisa personalizada

2010/12/11

BeanShell: Patch to do it work with enum in switch/case statements

I really like BeanShell. But it is based in pre-Java1.5. So, there is some new Java language features, like enumerations and generics, that it doesn't allow to use. I have made a plugin to use it with Netbeans and I have included it in several projects that I develop, since 2006/2007, I think. I use it into my applications like I use VBA into Microsoft Office stuffs. With BeanShell is easy to do several things without recompile or shutdown your application. You can query, prototype, test, simulate, plugin, plugout, automate and do many things with it. I really like it. I know that Java have has officially incorporated support to scripting, but BeanShell is Java... so if I need to reuse my code later in Java, is simple as to do: nothing! Yeah, it's true. 'cause bsh can load .java file sources, also. So, the sky isn't the limit; the limit is you!

BeanShell Patch to work with enums in switch statements

The patch is to be applied into the file class BSHSwitchStatement. See bellow just the lines affected by it:
 62         //marciowb 2010-12-11 patch to allows the Bsh to works with enum with switchs statements.
 63         //it breaks the compatibility versions of Java older than 1.5, but it works.
 64         final Class switchValClass = switchVal.getClass();               //What's the class of the value of this switch?
 65         final boolean switchValIsEnumType = switchValClass.isEnum();     //Is it a enum type?
 66 
 67         // while more labels or blocks and haven't hit return control
 68         while (child < numchild && returnControl == null) {
 69 
 70             Object labelValue = label.isDefault ? null
 71                                 : (switchValIsEnumType //If it is a enum type,
 72                                    ? Enum.valueOf(switchValClass, label.getChild(0).getText().trim()) //then get the enum value
 73                                    : label.eval(callstack, interpreter));                //otherwise, gonna default evaluation...
 74 
 75             // if label is default or equals switchVal
 76             if (label.isDefault || primitiveEquals(switchVal, labelValue, callstack, switchExp)) {


Now, if you want the entire file:
  1 /*****************************************************************************
  2  *                                                                           *
  3  *  This file is part of the BeanShell Java Scripting distribution.          *
  4  *  Documentation and updates may be found at http://www.beanshell.org/      *
  5  *                                                                           *
  6  *  Sun Public License Notice:                                               *
  7  *                                                                           *
  8  *  The contents of this file are subject to the Sun Public License Version  *
  9  *  1.0 (the "License"); you may not use this file except in compliance with *
 10  *  the License. A copy of the License is available at http://www.sun.com    * 
 11  *                                                                           *
 12  *  The Original Code is BeanShell. The Initial Developer of the Original    *
 13  *  Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright     *
 14  *  (C) 2000.  All Rights Reserved.                                          *
 15  *                                                                           *
 16  *  GNU Public License Notice:                                               *
 17  *                                                                           *
 18  *  Alternatively, the contents of this file may be used under the terms of  *
 19  *  the GNU Lesser General Public License (the "LGPL"), in which case the    *
 20  *  provisions of LGPL are applicable instead of those above. If you wish to *
 21  *  allow use of your version of this file only under the  terms of the LGPL *
 22  *  and not to allow others to use your version of this file under the SPL,  *
 23  *  indicate your decision by deleting the provisions above and replace      *
 24  *  them with the notice and other provisions required by the LGPL.  If you  *
 25  *  do not delete the provisions above, a recipient may use your version of  *
 26  *  this file under either the SPL or the LGPL.                              *
 27  *                                                                           *
 28  *  Patrick Niemeyer (pat@pat.net)                                           *
 29  *  Author of Learning Java, O'Reilly & Associates                           *
 30  *  http://www.pat.net/~pat/                                                 *
 31  *                                                                           *
 32  *****************************************************************************/
 33 package bsh;
 34 
 35 public class BSHSwitchStatement extends SimpleNode implements ParserConstants {
 36 
 37     public BSHSwitchStatement(int id) {
 38         super(id);
 39     }
 40 
 41     public Object eval(CallStack callstack, Interpreter interpreter) throws EvalError {
 42         int numchild = jjtGetNumChildren();
 43         int child = 0;
 44         SimpleNode switchExp = ((SimpleNode) jjtGetChild(child++));
 45         Object switchVal = switchExp.eval(callstack, interpreter);
 46 
 47         /*
 48         Note: this could be made clearer by adding an inner class for the
 49         cases and an object context for the child traversal.
 50          */
 51         // first label
 52         BSHSwitchLabel label;
 53         Object node;
 54         ReturnControl returnControl = null;
 55 
 56         // get the first label
 57         if (child >= numchild) {
 58             throw new EvalError("Empty switch statement.", this, callstack);
 59         }
 60         label = ((BSHSwitchLabel) jjtGetChild(child++));
 61 
 62         //marciowb 2010-12-11 patch to allows the Bsh to works with enum with switchs statements.
 63         //it breaks the compatibility versions of Java older than 1.5, but it works.
 64         final Class switchValClass = switchVal.getClass();               //What's the class of the value of this switch?
 65         final boolean switchValIsEnumType = switchValClass.isEnum();     //Is it a enum type?
 66 
 67         // while more labels or blocks and haven't hit return control
 68         while (child < numchild && returnControl == null) {
 69 
 70             Object labelValue = label.isDefault ? null
 71                                 : (switchValIsEnumType //If it is a enum type,
 72                                    ? Enum.valueOf(switchValClass, label.getChild(0).getText().trim()) //then get the enum value
 73                                    : label.eval(callstack, interpreter));                //otherwise, gonna default evaluation...
 74 
 75             // if label is default or equals switchVal
 76             if (label.isDefault || primitiveEquals(switchVal, labelValue, callstack, switchExp)) {
 77                 // execute nodes, skipping labels, until a break or return
 78                 while (child < numchild) {
 79                     node = jjtGetChild(child++);
 80                     if (node instanceof BSHSwitchLabel) {
 81                         continue;
 82                     }
 83                     // eval it
 84                     Object value = ((SimpleNode) node).eval(callstack, interpreter);
 85 
 86                     // should check to disallow continue here?
 87                     if (value instanceof ReturnControl) {
 88                         returnControl = (ReturnControl) value;
 89                         break;
 90                     }
 91                 }
 92             } else {
 93                 // skip nodes until next label
 94                 while (child < numchild) {
 95                     node = jjtGetChild(child++);
 96                     if (node instanceof BSHSwitchLabel) {
 97                         label = (BSHSwitchLabel) node;
 98                         break;
 99                     }
100                 }
101             }
102         }
103 
104         if (returnControl != null && returnControl.kind == RETURN) {
105             return returnControl;
106         } else {
107             return Primitive.VOID;
108         }
109     }
110 
111     /**
112     Helper method for testing equals on two primitive or boxable objects.
113     yuck: factor this out into Primitive.java
114      */
115     private boolean primitiveEquals(Object switchVal, Object targetVal, CallStack callstack,
116                                     SimpleNode switchExp)
117             throws EvalError {
118         if (switchVal instanceof Primitive || targetVal instanceof Primitive) {
119             try {
120                 // binaryOperation can return Primitive or wrapper type
121                 Object result = Primitive.binaryOperation(
122                         switchVal, targetVal, ParserConstants.EQ);
123                 result = Primitive.unwrap(result);
124                 return result.equals(Boolean.TRUE);
125             } catch (UtilEvalError e) {
126                 throw e.toEvalError(
127                         "Switch value: " + switchExp.getText() + ": ",
128                         this, callstack);
129             }
130         } else {
131             return switchVal.equals(targetVal);
132         }
133     }
134 }
135 
136 


Using the patch, you can use codes like this:
        for (S52DrawInstruction ins : drawIns) {
            switch (ins.getType()) { 
                case AC:
                    final S52DrawAreaColor ac = (S52DrawAreaColor) ins;
                    poly.setFillPaint(ac.color.color);
                    break;

                case LS:
                    final S52DrawLineStyle ls = (S52DrawLineStyle) ins;
                    poly.setLinePaint(ls.color.color);
                    BasicStroke stroke;
                    stroke = helper.getStroke(ls.width, ls.style);
                    poly.setStroke(stroke);
                    break;

                case CS:
                    final S52DrawComplex cs = (S52DrawComplex) ins;
                    final String simpleInstructions = getDrawInstructionsFromComplex(fe, cs);
                    if (simpleInstructions == null) {
                        info("Não obtívemos as instruções de desenho simplificadas para a instrução complexa: " + cs + " de " + fe);
                        return;
                    }
                    final S52DrawInstructions simpleDrawIns = scat.parseDrawInstructions(simpleInstructions);
                    configGraphic(poly, fe, co, symb, sp, simpleDrawIns);
                    break;

                default:
                    info("Simbologia não tratada: " + ins);
            }
        }

Where the method getType() returns a enum value from the enumeration bellow:
 1 package com.solvoj.S52Library;
 2 
 3 /**
 4  * List of S52 Symbolization Instruction.
 5  *
 6  * @author Marcio Wesley Borges, 2010-12-07 Niterói-RJ
 7  */
 8 public enum S52DrawInstructionEnum {
 9 
10     /** line drawing styles (simple ones (LS) for variable width coloured lines */
11     LS(new S52DrawLineStyle.Factory()),
12     /** complex line-styles (LC), where line is visualized by a repetitive pattern) */
13     LC(new S52DrawLineComplex.Factory()),
14     /** area fill instructions, either with one color (AC, four levels of transparency) */
15     AC(new S52DrawAreaColor.Factory()),
16     /** area with repetition of pattern symbols (AP). */
17     AP(new S52DrawAreaPattern.Factory()),
18     /** symbols for point locationsSY. */
19     SY(new S52DrawSymbol.Factory()),
20     /** text drawing instructions with selectable font family, size, and justification */
21     TX(new S52DrawText.Factory()),
22     /** text drawing instructions with selectable font family, size, and justification */
23     TE(new S52DrawTextExtended.Factory()),
24     /**
25      * complex symbolization primitives (CS) provide hooks for external functions (from a
26      * dynamically loadable library) that can provide more complicated symbolizations than
27      * the look-up tables of the presentation library. Complex symbolization procedures can
28      * also take advantage on the user-changeable presentation parameters for providing more
29      * dynamic visualization.
30      */
31     CS(new S52DrawComplex.Factory());
32 
33     final S52DrawInstruction.Factory<?> factory;
34 
35     private S52DrawInstructionEnum(S52DrawInstruction.Factory<?> instructionParser) {
36         this.factory = instructionParser;
37     }
38 
39     public S52DrawInstruction.Factory<?> getFactory() {
40         return factory;
41     }
42 
43     @Override
44     public String toString() {
45         return name() + " class " + getFactory().getClass().getEnclosingClass().getSimpleName();
46     }
47 }//end of enum S52DrawInstructionEnum
48 
49 

Labels: , ,

0 Comments:

Post a Comment

<< Home