Source Code Cross Referenced for Runtime.java in  » Scripting » Pnuts » pnuts » lang » 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 » Scripting » Pnuts » pnuts.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Runtime.java
0003:         *
0004:         * Copyright (c) 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
0005:         *
0006:         * See the file "LICENSE.txt" for information on usage and redistribution
0007:         * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
0008:         */
0009:        package pnuts.lang;
0010:
0011:        import java.io.File;
0012:        import java.io.FileNotFoundException;
0013:        import java.io.IOException;
0014:        import java.io.InputStream;
0015:        import java.io.InputStreamReader;
0016:        import java.io.PrintWriter;
0017:        import java.io.Reader;
0018:        import java.io.StringReader;
0019:        import java.io.Serializable;
0020:        import java.io.ObjectInputStream;
0021:        import java.io.ObjectOutputStream;
0022:        import java.io.UnsupportedEncodingException;
0023:        import java.lang.reflect.Array;
0024:        import java.lang.reflect.Constructor;
0025:        import java.lang.reflect.Field;
0026:        import java.lang.reflect.InvocationTargetException;
0027:        import java.lang.reflect.Method;
0028:        import java.lang.reflect.Modifier;
0029:        import java.math.BigDecimal;
0030:        import java.math.BigInteger;
0031:        import java.net.URL;
0032:        import java.net.URLConnection;
0033:        import java.security.AccessController;
0034:        import java.security.PrivilegedAction;
0035:        import java.security.PrivilegedActionException;
0036:        import java.security.PrivilegedExceptionAction;
0037:        import java.text.DateFormat;
0038:        import java.text.MessageFormat;
0039:        import java.util.Calendar;
0040:        import java.util.Enumeration;
0041:        import java.util.HashMap;
0042:        import java.util.HashSet;
0043:        import java.util.Hashtable;
0044:        import java.util.Map;
0045:        import java.util.WeakHashMap;
0046:        import java.util.List;
0047:        import java.util.ArrayList;
0048:        import java.util.MissingResourceException;
0049:        import java.util.Properties;
0050:        import java.util.ResourceBundle;
0051:        import java.util.Set;
0052:        import java.util.Iterator;
0053:        import java.beans.PropertyChangeListener;
0054:        import java.beans.PropertyChangeEvent;
0055:
0056:        import org.pnuts.lang.UnparseVisitor;
0057:        import org.pnuts.lang.NodeUtil;
0058:        import org.pnuts.lang.*;
0059:        import org.pnuts.util.Stack;
0060:        import org.pnuts.util.*;
0061:
0062:        /**
0063:         * This class provides runtime supports for Pnuts compiler/interpreter. Most of
0064:         * the methods are protected static, so that only subclasses can access them.
0065:         */
0066:        public class Runtime implements  Executable {
0067:
0068:            private final static boolean DEBUG = false;
0069:
0070:            private final static Object[] noarg = new Object[] {};
0071:
0072:            protected static final String INT_SYMBOL = "int".intern();
0073:
0074:            protected static final String SHORT_SYMBOL = "short".intern();
0075:
0076:            protected static final String CHAR_SYMBOL = "char".intern();
0077:
0078:            protected static final String BYTE_SYMBOL = "byte".intern();
0079:
0080:            protected static final String LONG_SYMBOL = "long".intern();
0081:
0082:            protected static final String FLOAT_SYMBOL = "float".intern();
0083:
0084:            protected static final String DOUBLE_SYMBOL = "double".intern();
0085:
0086:            protected static final String BOOLEAN_SYMBOL = "boolean".intern();
0087:
0088:            protected static final String VOID_SYMBOL = "void".intern();
0089:
0090:            protected static final String CLONE = "clone".intern();
0091:
0092:            protected static final String EXCEPTOIN_FIELD_SYMBOL = "$exception$"
0093:                    .intern();
0094:
0095:            private final static String DEFAULT_PROPERTY_FILE = "runtime.properties";
0096:
0097:            private final static Integer ZERO = new Integer(0);
0098:
0099:            protected final static Object[] NO_PARAM = new Object[0];
0100:
0101:            private static Properties defaultProperties;
0102:
0103:            /**/
0104:            static {
0105:                try {
0106:                    AccessController.doPrivileged(new PrivilegedAction() {
0107:                        public Object run() {
0108:                            InputStream in = Runtime.class
0109:                                    .getResourceAsStream(DEFAULT_PROPERTY_FILE);
0110:                            if (in != null) {
0111:                                Properties prop = new Properties();
0112:                                try {
0113:                                    prop.load(in);
0114:                                    defaultProperties = prop;
0115:                                } catch (IOException ioe) {
0116:                                    // ignore
0117:                                }
0118:                            }
0119:                            return null;
0120:                        }
0121:                    });
0122:                } catch (Exception e) {
0123:                    // ignore
0124:                }
0125:            }
0126:
0127:            /**/
0128:
0129:            public static boolean getBoolean(final String key) {
0130:                Boolean b = (Boolean) AccessController
0131:                        .doPrivileged(new PrivilegedAction() {
0132:                            public Object run() {
0133:                                String sval = Runtime.getProperty(key);
0134:                                if (sval != null
0135:                                        && sval.equalsIgnoreCase("true")) {
0136:                                    return Boolean.TRUE;
0137:                                } else {
0138:                                    return Boolean.FALSE;
0139:                                }
0140:                            }
0141:                        });
0142:                return b.booleanValue();
0143:            }
0144:
0145:            protected Runtime() {
0146:            }
0147:
0148:            public static Runtime getDefaultRuntime() {
0149:                if (getBoolean("pnuts.compiler.useDynamicProxy")) {
0150:                    return new pnuts.compiler.DynamicRuntime();
0151:                } else {
0152:                    return new Runtime();
0153:                }
0154:            }
0155:
0156:            /**
0157:             * Executes a compiled script. Exceptions are checked if an exception
0158:             * handler is registered with the catch() function. Output stream of the
0159:             * specified context is flushed after the script is executed or an exception
0160:             * is thrown.
0161:             * 
0162:             * @param context
0163:             *            the context in which this object is executed
0164:             * @return the result of the execution
0165:             */
0166:            public Object run(Context context) {
0167:                if (DEBUG) {
0168:                    System.out.println("runtime is "
0169:                            + this .getClass().getSuperclass());
0170:                }
0171:                context.runtime = this ;
0172:                try {
0173:                    return exec(context);
0174:                } catch (Throwable t) {
0175:                    checkException(context, t);
0176:                    return null;
0177:                } finally {
0178:                    PrintWriter pw = context.getWriter();
0179:                    if (pw != null) {
0180:                        pw.flush();
0181:                    }
0182:                }
0183:            }
0184:
0185:            /**
0186:             * Executes a compiled script. Exceptions are checked if an exception
0187:             * handler is registered with the catch() function. Output stream of the
0188:             * specified context is flushed after the script is executed or an exception
0189:             * is thrown.
0190:             * 
0191:             * @param context
0192:             *            the context in which this object is executed
0193:             * @return the result of the execution
0194:             * 
0195:             * @deprecated replaced by run(Context)
0196:             */
0197:            public Object execute(Context context) {
0198:                return run(context);
0199:            }
0200:
0201:            /**
0202:             * This method is overrided by classes generated by the compiler.
0203:             * 
0204:             * @param context
0205:             *            the context in which this object is executed
0206:             * @return the result of the execution
0207:             */
0208:            protected Object exec(Context context) {
0209:                return null;
0210:            }
0211:
0212:            /**
0213:             * Call a method
0214:             * 
0215:             * @param context
0216:             *            the context in which the method is called
0217:             * @param c
0218:             *            the class of method
0219:             * @param name
0220:             *            the method name
0221:             * @param args
0222:             *            the paramters
0223:             * @param types
0224:             *            the types of the paramters
0225:             * @param target
0226:             *            the target object
0227:             * @return the return value of the call
0228:             */
0229:            public static Object callMethod(Context context, Class c,
0230:                    String name, Object args[], Class types[], Object target) {
0231:                return context.config.callMethod(context, c, name, args, types,
0232:                        target);
0233:            }
0234:
0235:            /**
0236:             * Call a constructor
0237:             * 
0238:             * @param context
0239:             *            the context in which the constructor is called
0240:             * @param c
0241:             *            the class of method
0242:             * @param args
0243:             *            the paramters
0244:             * @param types
0245:             *            the types of the formal arguments
0246:             * @return the created instance
0247:             */
0248:            public static Object callConstructor(Context context, Class c,
0249:                    Object args[], Class types[]) {
0250:                return context.config.callConstructor(context, c, args, types);
0251:            }
0252:
0253:            /**
0254:             * Call a method
0255:             * 
0256:             * @param context
0257:             *            the context
0258:             * @param c
0259:             *            the class of method
0260:             * @param name
0261:             *            the method name
0262:             * @param args
0263:             *            the paramters
0264:             * @param types
0265:             *            the types of the formal arguments
0266:             * @param target
0267:             *            the target object
0268:             * @return the return value
0269:             */
0270:            protected Object _callMethod(Context context, Class c, String name,
0271:                    Object args[], Class types[], Object target) {
0272:                Method method = null;
0273:                boolean _static = (target == null);
0274:
0275:                if (name == CLONE && args.length == 0) {
0276:                    if (target instanceof  Object[]) {
0277:                        return ((Object[]) target).clone();
0278:                    } else if (target instanceof  int[]) {
0279:                        return ((int[]) target).clone();
0280:                    } else if (target instanceof  byte[]) {
0281:                        return ((byte[]) target).clone();
0282:                    } else if (target instanceof  short[]) {
0283:                        return ((short[]) target).clone();
0284:                    } else if (target instanceof  char[]) {
0285:                        return ((char[]) target).clone();
0286:                    } else if (target instanceof  long[]) {
0287:                        return ((long[]) target).clone();
0288:                    } else if (target instanceof  float[]) {
0289:                        return ((float[]) target).clone();
0290:                    } else if (target instanceof  double[]) {
0291:                        return ((double[]) target).clone();
0292:                    } else if (target instanceof  boolean[]) {
0293:                        return ((boolean[]) target).clone();
0294:                    }
0295:                }
0296:                Method m[] = context.config._getMethods(c, name);
0297:
0298:                try {
0299:                    int count = 0;
0300:                    int min = Integer.MAX_VALUE;
0301:                    Stack methods = new Stack();
0302:                    cand: for (int i = 0; i < m.length; i++) {
0303:                        Method mi = m[i];
0304:                        Class p[] = mi.getParameterTypes();
0305:                        if (p.length != args.length) {
0306:                            continue;
0307:                        }
0308:                        count = 0;
0309:                        for (int j = 0; j < p.length; j++) {
0310:                            Class pj = p[j];
0311:                            if (types != null) {
0312:                                Class tj = types[j];
0313:                                if (tj != null && pj != tj
0314:                                        && !pj.isAssignableFrom(tj)) {
0315:                                    continue cand;
0316:                                }
0317:                            }
0318:                            int t = matchType(pj, args[j]);
0319:                            if (t < 0) {
0320:                                continue cand;
0321:                            }
0322:                            count += t;
0323:                        }
0324:                        if (count > min) {
0325:                            continue;
0326:                        }
0327:
0328:                        boolean st = Modifier.isStatic(mi.getModifiers());
0329:                        if (st != _static) {
0330:                            continue;
0331:                        }
0332:
0333:                        if (count < min) {
0334:                            methods.removeAllElements();
0335:                            methods.push(mi);
0336:                            min = count;
0337:                        } else if (count == min) {
0338:                            methods.push(mi);
0339:                        }
0340:                    }
0341:                    Class clazz = c;
0342:                    out: while (clazz != null) {
0343:                        int size = methods.size();
0344:                        for (int i = 0; i < size; i++) {
0345:                            method = (Method) methods.pop();
0346:                            if (!_static && method.getDeclaringClass() == clazz) {
0347:                                break out;
0348:                            }
0349:                        }
0350:                        clazz = clazz.getSuperclass();
0351:                    }
0352:
0353:                    if (method != null) {
0354:                        if (args.length > 0) {
0355:                            Class p[] = method.getParameterTypes();
0356:                            for (int j = 0; j < p.length; j++) {
0357:                                Class pj = p[j];
0358:                                if (args[j] != null
0359:                                        && isArray(args[j])
0360:                                        && (pj.isArray() || List.class
0361:                                                .isAssignableFrom(pj))) {
0362:                                    if (!pj.isInstance(args[j])) {
0363:                                        args[j] = transform(pj, args[j],
0364:                                                context);
0365:                                    }
0366:                                }
0367:                            }
0368:                        }
0369:                        try {
0370:                            return method.invoke(target, args);
0371:                        } catch (InvocationTargetException ita) {
0372:                            Throwable t = ita.getTargetException();
0373:                            if (t instanceof  PnutsException) {
0374:                                throw (PnutsException) t;
0375:                            } else {
0376:                                throw new PnutsException(t, context);
0377:                            }
0378:                        }
0379:                    } else {
0380:                        if (target instanceof  Class) {
0381:                            Class cls = (Class) target;
0382:                            return _callMethod(context, (Class) target, name,
0383:                                    args, types, null);
0384:                        }
0385:
0386:                        throw new PnutsException("method.notFound",
0387:                                new Object[] { name,
0388:                                        "" + (target == null ? c : target),
0389:                                        "" + Pnuts.format(args) }, context);
0390:                    }
0391:                } catch (IllegalAccessException pe) {
0392:                    Class cls = method.getDeclaringClass();
0393:                    try {
0394:                        if (!Modifier.isPublic(cls.getModifiers())) {
0395:                            Method _m = findCallableMethod(cls, name, method
0396:                                    .getParameterTypes());
0397:                            if (_m != null) {
0398:                                for (int i = 0; i < m.length; i++) {
0399:                                    if (m[i] == method) {
0400:                                        if (DEBUG) {
0401:                                            System.out.println(_m + " <- "
0402:                                                    + method);
0403:                                        }
0404:                                        m[i] = _m;
0405:                                        break;
0406:                                    }
0407:                                }
0408:                                return _m.invoke(target, args);
0409:                            }
0410:                        }
0411:                        return Configuration.normalConfiguration.reInvoke(pe,
0412:                                method, target, args);
0413:                    } catch (IllegalAccessException iae) {
0414:                        throw new PnutsException(iae, context);
0415:                    } catch (InvocationTargetException ita) {
0416:                        Throwable t = ita.getTargetException();
0417:                        if (t instanceof  PnutsException) {
0418:                            throw (PnutsException) t;
0419:                        } else {
0420:                            throw new PnutsException(t, context);
0421:                        }
0422:                    }
0423:                } catch (PnutsException pe) {
0424:                    throw pe;
0425:                } catch (Exception e) {
0426:                    throw new PnutsException(e, context);
0427:                }
0428:            }
0429:
0430:            protected static Method findCallableMethod(Class clazz,
0431:                    String name, Class args[]) {
0432:                while (clazz != null) {
0433:                    Method method;
0434:                    if (Modifier.isPublic(clazz.getModifiers())) {
0435:                        try {
0436:                            method = clazz.getMethod(name, args);
0437:                            if (method != null
0438:                                    && Modifier
0439:                                            .isPublic(method
0440:                                                    .getDeclaringClass()
0441:                                                    .getModifiers())) {
0442:                                return method;
0443:                            }
0444:                        } catch (NoSuchMethodException nme) {
0445:                        }
0446:                    }
0447:                    Class it[] = clazz.getInterfaces();
0448:                    for (int i = 0; i < it.length; i++) {
0449:                        Method m = findCallableMethod(it[i], name, args);
0450:                        if (m != null) {
0451:                            return m;
0452:                        }
0453:                    }
0454:                    clazz = clazz.getSuperclass();
0455:                }
0456:                return null;
0457:            }
0458:
0459:            /**
0460:             * Call a constructor
0461:             * 
0462:             * @param context
0463:             *            the context in which the constructor is called
0464:             * @param c
0465:             *            the class of method
0466:             * @param args
0467:             *            the paramters
0468:             * @param types
0469:             *            the types of the formal arguments
0470:             * @return the created instance
0471:             */
0472:            protected Object _callConstructor(Context context, Class c,
0473:                    Object args[], Class types[]) {
0474:                try {
0475:                    Constructor cs[] = context.config._getConstructors(c);
0476:
0477:                    Constructor cons = null;
0478:                    int count = 0;
0479:                    int min = Integer.MAX_VALUE;
0480:                    cand: for (int i = 0; i < cs.length; i++) {
0481:                        Class p[] = cs[i].getParameterTypes();
0482:                        if (p.length != args.length) {
0483:                            continue;
0484:                        }
0485:                        count = 0;
0486:                        for (int j = 0; j < p.length; j++) {
0487:                            Class pj = p[j];
0488:                            if (types != null) {
0489:                                Class tj = types[j];
0490:                                if (tj != null && pj != tj
0491:                                        && !pj.isAssignableFrom(tj)) {
0492:                                    continue cand;
0493:                                }
0494:                            }
0495:                            int t = matchType(pj, args[j]);
0496:                            if (t < 0) {
0497:                                continue cand;
0498:                            }
0499:                            count += t;
0500:                        }
0501:                        if (count < min) {
0502:                            min = count;
0503:                            cons = cs[i];
0504:                        }
0505:                    }
0506:                    if (cons != null) {
0507:                        Class p[] = cons.getParameterTypes();
0508:                        for (int j = 0; j < p.length; j++) {
0509:                            Class pj = p[j];
0510:                            if (args[j] != null
0511:                                    && isArray(args[j])
0512:                                    && (pj.isArray() || List.class
0513:                                            .isAssignableFrom(pj))) {
0514:                                if (!pj.isInstance(args[j])) {
0515:                                    args[j] = transform(pj, args[j], context);
0516:                                }
0517:                            }
0518:                        }
0519:                        try {
0520:                            return cons.newInstance(args);
0521:                        } catch (InvocationTargetException ita) {
0522:                            Throwable t = ita.getTargetException();
0523:                            if (t instanceof  PnutsException) {
0524:                                throw (PnutsException) t;
0525:                            } else {
0526:                                throw new PnutsException(t, context);
0527:                            }
0528:                        }
0529:                    } else {
0530:                        throw new IllegalArgumentException();
0531:                    }
0532:                } catch (IllegalArgumentException e2) {
0533:                    throw new PnutsException("constructor.notFound",
0534:                            new Object[] { c, Pnuts.format(args) }, context);
0535:                } catch (PnutsException e3) {
0536:                    throw e3;
0537:                } catch (Throwable e4) {
0538:                    throw new PnutsException(e4, context);
0539:                }
0540:            }
0541:
0542:            /**
0543:             * Assign an object to a static field.
0544:             * 
0545:             * @param context
0546:             *            the context in which the field is accessed
0547:             * @param clazz
0548:             *            the class in which the static field is defined
0549:             * @param name
0550:             *            the name of the static field
0551:             * @param expr
0552:             *            the value to be assigned
0553:             */
0554:            public static void putStaticField(Context context, Class clazz,
0555:                    String name, Object expr) {
0556:                context.config.putStaticField(context, clazz, name, expr);
0557:            }
0558:
0559:            /**
0560:             * Get the value of a static field.
0561:             * 
0562:             * @param context
0563:             *            the context in which the field is accessed
0564:             * @param clazz
0565:             *            the class in which the static field is defined
0566:             * @param name
0567:             *            the name of the static field
0568:             * @return the value
0569:             */
0570:            public static Object getStaticField(Context context, Class clazz,
0571:                    String name) {
0572:                return context.config.getStaticField(context, clazz, name);
0573:            }
0574:
0575:            /**
0576:             * Assign an object to a instance field.
0577:             * 
0578:             * @param context
0579:             *            the context in which the field is accessed
0580:             * @param target
0581:             *            the target object of the field
0582:             * @param name
0583:             *            the name of the field
0584:             * @param expr
0585:             *            the value to be assigned
0586:             */
0587:            public static void putField(Context context, Object target,
0588:                    String name, Object expr) {
0589:                context.config.putField(context, target, name, expr);
0590:            }
0591:
0592:            /**
0593:             * Get the value of a instance field.
0594:             * 
0595:             * @param context
0596:             *            the context in which the field is accessed
0597:             * @param target
0598:             *            the target object of the field
0599:             * @param name
0600:             *            the name of the field
0601:             * @return the value
0602:             */
0603:            public static Object getField(Context context, Object target,
0604:                    String name) {
0605:                return context.config.getField(context, target, name);
0606:            }
0607:
0608:            protected Object _getField(Context context, Class c, String name,
0609:                    Object target) {
0610:                try {
0611:                    Field f = getField(target.getClass(), name);
0612:                    if (f == null) {
0613:                        throw new PnutsException("field.notFound",
0614:                                new Object[] { name, target }, context);
0615:                    }
0616:                    return f.get(target);
0617:                } catch (PnutsException pe) {
0618:                    throw pe;
0619:                } catch (Exception e) {
0620:                    throw new PnutsException(e, context);
0621:                }
0622:            }
0623:
0624:            protected void _putField(Context context, Class cls, String name,
0625:                    Object target, Object value) {
0626:                try {
0627:                    Field f = getField(target.getClass(), name);
0628:                    if (f == null) {
0629:                        throw new PnutsException("field.notFound",
0630:                                new Object[] { name, target }, context);
0631:                    }
0632:                    f.set(target, value);
0633:                } catch (PnutsException pe) {
0634:                    throw pe;
0635:                } catch (Exception e) {
0636:                    throw new PnutsException(e, context);
0637:                }
0638:            }
0639:
0640:            /**
0641:             * Get true component type from an array type. e.g. int[][] ==> int,
0642:             * String[] ==> String
0643:             * 
0644:             * @param clazz
0645:             *            An array type to be examined
0646:             * @return The component type of the array type.
0647:             */
0648:            public static Class getBottomType(Class clazz) {
0649:                while (clazz.isArray()) {
0650:                    clazz = clazz.getComponentType();
0651:                }
0652:                return clazz;
0653:            }
0654:
0655:            /**
0656:             * Creates an array type
0657:             * 
0658:             * @param c
0659:             *            the component type
0660:             * @param dim
0661:             *            the number of dimensions
0662:             */
0663:            public static Class arrayType(Class c, int dim) {
0664:                if (dim == 0) {
0665:                    return c;
0666:                } else {
0667:                    return arrayType(Array.newInstance(c, 0).getClass(),
0668:                            dim - 1);
0669:                }
0670:            }
0671:
0672:            protected static int arraydim(Object o) {
0673:                if (isArray(o)) {
0674:                    int len = getArrayLength(o);
0675:                    int maxDim = 0;
0676:                    for (int i = 0; i < len; i++) {
0677:                        int dim = arraydim(Array.get(o, i));
0678:                        if (dim > maxDim) {
0679:                            maxDim = dim;
0680:                        }
0681:                    }
0682:                    return maxDim + 1;
0683:                } else {
0684:                    return 0;
0685:                }
0686:            }
0687:
0688:            public static Object transform(Class type, Object obj) {
0689:                return transform(type, obj, null);
0690:            }
0691:
0692:            public static Object transform(Class type, Object obj,
0693:                    Context context) {
0694:                if (type.isArray()) {
0695:                    boolean isList = (obj instanceof  List);
0696:                    boolean isArray = isArray(obj);
0697:                    if (obj != null && !(isList || isArray)) {
0698:                        return obj;
0699:                    }
0700:                    Class componentType = type.getComponentType();
0701:                    int len;
0702:                    if (isArray) {
0703:                        len = getArrayLength(obj);
0704:                    } else if (isList) {
0705:                        len = ((List) obj).size();
0706:                    } else {
0707:                        return obj;
0708:                    }
0709:                    Object result = Array.newInstance(componentType, len);
0710:                    for (int i = 0; i < len; i++) {
0711:                        Object elem = null;
0712:                        if (context != null) {
0713:                            elem = context.config.getElement(context, obj,
0714:                                    new Integer(i));
0715:                        } else {
0716:                            if (isArray) {
0717:                                elem = Array.get(obj, i);
0718:                            } else if (isList) {
0719:                                elem = ((List) obj).get(i);
0720:                            }
0721:                        }
0722:                        Array.set(result, i, transform(componentType, elem,
0723:                                context));
0724:                    }
0725:                    return result;
0726:                } else {
0727:                    // TODO
0728:                    if (type == byte.class) {
0729:                        if (!(obj instanceof  Byte) && obj instanceof  Number) {
0730:                            obj = new Byte(((Number) obj).byteValue());
0731:                        }
0732:                    } else if (type == short.class) {
0733:                        if (!(obj instanceof  Short) && obj instanceof  Number) {
0734:                            obj = new Short(((Number) obj).shortValue());
0735:                        }
0736:                    } else if (type == char.class) {
0737:                        if (obj instanceof  Number) {
0738:                            obj = new Character((char) ((Number) obj)
0739:                                    .intValue());
0740:                        }
0741:                    } else if (List.class.isAssignableFrom(type)) {
0742:                        if (isArray(obj)) {
0743:                            int len = getArrayLength(obj);
0744:                            try {
0745:                                List list;
0746:                                if (type.isInterface()) {
0747:                                    list = new ArrayList();
0748:                                    if (!type.isInstance(list)) {
0749:                                        throw new IllegalArgumentException();
0750:                                    }
0751:                                } else {
0752:                                    list = (List) type.newInstance();
0753:                                }
0754:                                for (int i = 0; i < len; i++) {
0755:                                    list.add(Array.get(obj, i));
0756:                                }
0757:                                return list;
0758:                            } catch (Exception e) {
0759:                                throw new IllegalArgumentException(e);
0760:                            }
0761:                        }
0762:                    }
0763:                    return obj;
0764:                }
0765:            }
0766:
0767:            protected static int matchType(Class type, Object obj) {
0768:                if (obj == null) {
0769:                    if (type.isPrimitive()) {
0770:                        return -1;
0771:                    }
0772:                    return 0;
0773:                }
0774:                Class clazz = obj.getClass();
0775:                if (clazz == type) {
0776:                    return 0;
0777:                }
0778:                if (type == boolean.class) {
0779:                    return (clazz == Boolean.class) ? 0 : -1;
0780:                }
0781:                if (type == byte.class) {
0782:                    return distance(0, clazz);
0783:                }
0784:                if (type == char.class) {
0785:                    return distance(6, clazz);
0786:                }
0787:                if (type == short.class) {
0788:                    return distance(1, clazz);
0789:                }
0790:                if (type == int.class) {
0791:                    return distance(2, clazz);
0792:                }
0793:                if (type == long.class) {
0794:                    return distance(3, clazz);
0795:                }
0796:                if (type == float.class) {
0797:                    return distance(4, clazz);
0798:                }
0799:                if (type == double.class) {
0800:                    return distance(5, clazz);
0801:                }
0802:                if (type.isAssignableFrom(clazz)) {
0803:                    return 1;
0804:                } else if (clazz.isArray()) {
0805:                    if (type.isArray()) {
0806:                        int j = 1;
0807:                        for (int i = 0; i < getArrayLength(obj); i++) {
0808:                            int s = matchType(type.getComponentType(), Array
0809:                                    .get(obj, i));
0810:                            if (s < 0) {
0811:                                return -1;
0812:                            } else {
0813:                                j += s;
0814:                            }
0815:                        }
0816:                        return j;
0817:                    } else if (List.class.isAssignableFrom(type)) {
0818:                        return 1;
0819:                    }
0820:                } else if (type.isArray()) {
0821:                    if (obj instanceof  List) {
0822:                        int j = 1;
0823:                        List list = (List) obj;
0824:                        for (int i = 0; i < list.size(); i++) {
0825:                            int s = matchType(type.getComponentType(), list
0826:                                    .get(i));
0827:                            if (s < 0) {
0828:                                return -1;
0829:                            } else {
0830:                                j += s;
0831:                            }
0832:                        }
0833:                        return j;
0834:                    }
0835:                }
0836:                return -1;
0837:            }
0838:
0839:            private final static int[][] distance_table = {
0840:                    { 0, 1, 2, 3, 4, 5, 1 }, { 1, 0, 1, 2, 3, 4, 2 },
0841:                    { 2, 2, 0, 1, 2, 3, 2 }, { 3, 3, 3, 0, 1, 2, -1 },
0842:                    { 4, 4, 4, 4, 0, 1, -1 }, { 5, 5, 5, 5, 5, 0, -1 },
0843:                    { 1, 2, 2, -1, -1, -1, 0 }, };
0844:
0845:            private static int distance(int pos, Class clazz) {
0846:                if (clazz == Double.class) {
0847:                    return distance_table[5][pos];
0848:                } else if (clazz == Float.class) {
0849:                    return distance_table[4][pos];
0850:                } else if (clazz == Long.class) {
0851:                    return distance_table[3][pos];
0852:                } else if (clazz == Integer.class) {
0853:                    return distance_table[2][pos];
0854:                } else if (clazz == Short.class) {
0855:                    return distance_table[1][pos];
0856:                } else if (clazz == Character.class) {
0857:                    return distance_table[6][pos];
0858:                } else if (clazz == Byte.class) {
0859:                    return distance_table[0][pos];
0860:                } else {
0861:                    return -1;
0862:                }
0863:            }
0864:
0865:            /*
0866:             * class <-> public methods
0867:             */
0868:            protected static Method[] getMethods(Context context, Class cls) {
0869:                return context.config.getMethods(cls);
0870:            }
0871:
0872:            /*
0873:             * class <-> Constructors
0874:             */
0875:            protected static Constructor[] getConstructors(Context context,
0876:                    Class cls) {
0877:                return context.config._getConstructors(cls);
0878:            }
0879:
0880:            /**
0881:             * Parse an integer.
0882:             * 
0883:             * @return an array [Number number, int offset_of_unit_symbol]
0884:             */
0885:            public static Object[] parseInt(String str) throws ParseException {
0886:                char c1 = str.charAt(0);
0887:                if (c1 == '#') {
0888:                    return parseInt(str.substring(1), 16, true);
0889:                } else if (c1 == '0') {
0890:                    if (str.length() > 1) {
0891:                        char c2 = str.charAt(1);
0892:                        if (c2 == 'x' || c2 == 'X') {
0893:                            return parseInt(str.substring(2), 16, false);
0894:                        } else {
0895:                            return parseInt(str, 8, false);
0896:                        }
0897:                    } else {
0898:                        return new Object[] { new Integer(0), null };
0899:                    }
0900:                } else {
0901:                    return parseInt(str, 10, false);
0902:                }
0903:            }
0904:
0905:            static Object[] parseInt(String str, int radix, boolean shrink)
0906:                    throws ParseException {
0907:                boolean overflow = false;
0908:                long value = 0;
0909:                int len = str.length();
0910:                int i = 0;
0911:                out: for (i = 0; i < len; i++) {
0912:                    int ch = str.charAt(i);
0913:                    switch (ch) {
0914:                    case '0':
0915:                    case '1':
0916:                    case '2':
0917:                    case '3':
0918:                    case '4':
0919:                    case '5':
0920:                    case '6':
0921:                    case '7':
0922:                        if (radix == 8) {
0923:                            value = (value << 3)
0924:                                    + Character.toLowerCase((char) ch) - '0';
0925:                            if (value < 0) {
0926:                                overflow = true;
0927:                                break out;
0928:                            }
0929:                            break;
0930:                        }
0931:                    case '8':
0932:                    case '9':
0933:                        if (radix == 10) {
0934:                            int c = ch - '0';
0935:                            value = (value * 10) + c;
0936:                            if (value < 0) {
0937:                                overflow = true;
0938:                                break out;
0939:                            }
0940:                            break;
0941:                        } else if (radix == 16) {
0942:                            value = (value << 4)
0943:                                    + Character.toLowerCase((char) ch) - '0';
0944:                            if (value < 0) {
0945:                                overflow = true;
0946:                                break out;
0947:                            }
0948:                            break;
0949:                        } else if (radix == 8) {
0950:                            throw new ParseException();
0951:                        }
0952:                    case 'a':
0953:                    case 'A':
0954:                    case 'b':
0955:                    case 'B':
0956:                    case 'c':
0957:                    case 'C':
0958:                    case 'd':
0959:                    case 'D':
0960:                    case 'e':
0961:                    case 'E':
0962:                    case 'f':
0963:                    case 'F':
0964:                        if (radix == 10) {
0965:                            break out;
0966:                        } else if (radix == 8) {
0967:                            throw new ParseException();
0968:                        }
0969:                        value = (value << 4) + 10
0970:                                + Character.toLowerCase((char) ch) - 'a';
0971:                        if (value < 0) {
0972:                            overflow = true;
0973:                            break out;
0974:                        }
0975:                        break;
0976:                    default:
0977:                        break out;
0978:                    }
0979:                }
0980:
0981:                out2: for (; i < len; i++) {
0982:                    int ch = str.charAt(i);
0983:                    switch (ch) {
0984:                    case '0':
0985:                    case '1':
0986:                    case '2':
0987:                    case '3':
0988:                    case '4':
0989:                    case '5':
0990:                    case '6':
0991:                    case '7':
0992:                    case '8':
0993:                    case '9':
0994:                        break;
0995:                    case 'a':
0996:                    case 'A':
0997:                    case 'b':
0998:                    case 'B':
0999:                    case 'c':
1000:                    case 'C':
1001:                    case 'd':
1002:                    case 'D':
1003:                    case 'e':
1004:                    case 'E':
1005:                    case 'f':
1006:                    case 'F':
1007:                        if (radix == 10) {
1008:                            break out2;
1009:                        }
1010:                        break;
1011:                    default:
1012:                        break out2;
1013:                    }
1014:                }
1015:
1016:                Number number = null;
1017:
1018:                if (overflow) {
1019:                    String s = str;
1020:                    if (str.length() > i) {
1021:                        s = str.substring(0, i);
1022:                    }
1023:                    number = decimalNumber(s, radix);
1024:                } else {
1025:                    if (value >= 0 && value <= 255 && radix == 16) {
1026:                        if (shrink) {
1027:                            number = new Byte((byte) value);
1028:                        } else {
1029:                            number = new Integer((int) value);
1030:                        }
1031:                    } else if (value <= Integer.MIN_VALUE
1032:                            || value >= Integer.MAX_VALUE) {
1033:                        number = new Long(value);
1034:                    } else {
1035:                        number = new Integer((int) value);
1036:                    }
1037:                }
1038:                if (str.length() > i) {
1039:                    if (radix == 16) {
1040:                        i += 2;
1041:                    }
1042:                    return new Object[] { number, new int[] { i } };
1043:                } else {
1044:                    return new Object[] { number, null };
1045:                }
1046:            }
1047:
1048:            /**
1049:             * Parse a floating point number.
1050:             * 
1051:             * @return an array [Number number, int offset_of_unit_symbol]
1052:             */
1053:            public static Object[] parseFloat(String str) {
1054:                int i = 0;
1055:                int len = str.length();
1056:                out1: for (i = 0; i < len; i++) {
1057:                    int ch = str.charAt(i);
1058:                    switch (ch) {
1059:                    case '0':
1060:                    case '1':
1061:                    case '2':
1062:                    case '3':
1063:                    case '4':
1064:                    case '5':
1065:                    case '6':
1066:                    case '7':
1067:                    case '8':
1068:                    case '9':
1069:                    case '.':
1070:                        break;
1071:                    default:
1072:                        break out1;
1073:                    }
1074:                }
1075:                if (i < len) {
1076:                    int ch = str.charAt(i);
1077:                    if (ch == 'e' || ch == 'E') {
1078:                        i++;
1079:                        out2: for (; i < len; i++) {
1080:                            ch = str.charAt(i);
1081:                            switch (ch) {
1082:                            case '+':
1083:                            case '-':
1084:                            case '0':
1085:                            case '1':
1086:                            case '2':
1087:                            case '3':
1088:                            case '4':
1089:                            case '5':
1090:                            case '6':
1091:                            case '7':
1092:                            case '8':
1093:                            case '9':
1094:                                break;
1095:                            default:
1096:                                break out2;
1097:                            }
1098:                        }
1099:                    }
1100:                }
1101:                String s = str;
1102:                if (i < len) {
1103:                    s = str.substring(0, i);
1104:                }
1105:                Number n = null;
1106:                if (s.length() > 16) {
1107:                    n = decimalNumber(s, 10);
1108:                } else {
1109:                    n = Double.valueOf(s);
1110:                }
1111:                if (i < len) {
1112:                    return new Object[] { n, new int[] { i } };
1113:                } else {
1114:                    return new Object[] { n, null };
1115:                }
1116:            }
1117:
1118:            /**
1119:             * Parse a string literal.
1120:             * 
1121:             * @return the value
1122:             */
1123:            public static String parseString(String str, int offset)
1124:                    throws ParseException {
1125:                StringBuffer buf = new StringBuffer();
1126:                int length = str.length();
1127:                for (int i = offset; i < length - offset; i++) {
1128:                    char ch = str.charAt(i);
1129:                    if (ch == '\\') {
1130:                        i++;
1131:                        switch (str.charAt(i)) {
1132:                        case '"':
1133:                            buf.append('"');
1134:                            break;
1135:                        case 'b':
1136:                            buf.append('\b');
1137:                            break;
1138:                        case 'f':
1139:                            buf.append('\f');
1140:                            break;
1141:                        case 't':
1142:                            buf.append('\t');
1143:                            break;
1144:                        case 'r':
1145:                            buf.append('\r');
1146:                            break;
1147:                        case 'n':
1148:                            buf.append('\n');
1149:                            break;
1150:                        case '0':
1151:                            buf.append('\0');
1152:                            break;
1153:                        case '\\':
1154:                            buf.append('\\');
1155:                            break;
1156:                        case 'u':
1157:                        case 'U': {
1158:                            if (i + 6 > length) {
1159:                                throw new ParseException();
1160:                            }
1161:                            int value = 0;
1162:                            for (int j = 0; j < 4; j++) {
1163:                                int c = str.charAt(++i);
1164:                                switch (c) {
1165:                                case '0':
1166:                                case '1':
1167:                                case '2':
1168:                                case '3':
1169:                                case '4':
1170:                                case '5':
1171:                                case '6':
1172:                                case '7':
1173:                                case '8':
1174:                                case '9':
1175:                                    value = (value << 4) + (c - '0');
1176:                                    break;
1177:                                case 'a':
1178:                                case 'A':
1179:                                case 'b':
1180:                                case 'B':
1181:                                case 'c':
1182:                                case 'C':
1183:                                case 'd':
1184:                                case 'D':
1185:                                case 'e':
1186:                                case 'E':
1187:                                case 'f':
1188:                                case 'F':
1189:                                    value = (value << 4) + 10
1190:                                            + Character.toLowerCase((char) c)
1191:                                            - 'a';
1192:                                    break;
1193:                                default:
1194:                                    throw new ParseException();
1195:                                }
1196:                            }
1197:                            buf.append((char) value);
1198:                            break;
1199:                        }
1200:                        default:
1201:                            throw new ParseException();
1202:                        }
1203:                    } else {
1204:                        buf.append(ch);
1205:                    }
1206:                }
1207:                return buf.toString();
1208:            }
1209:
1210:            /**
1211:             * Parse a character literal.
1212:             * 
1213:             * @return the value
1214:             */
1215:            public static Character parseChar(String str) throws ParseException {
1216:                if (str.charAt(1) == '\\') {
1217:                    switch (str.charAt(2)) {
1218:                    case '\'':
1219:                        return new Character('\'');
1220:                    case 'b':
1221:                        return new Character('\b');
1222:                    case 'f':
1223:                        return new Character('\f');
1224:                    case 't':
1225:                        return new Character('\t');
1226:                    case 'r':
1227:                        return new Character('\r');
1228:                    case 'n':
1229:                        return new Character('\n');
1230:                    case '0':
1231:                        return new Character('\0');
1232:                    case '\\':
1233:                        return new Character('\\');
1234:                    case 'u':
1235:                    case 'U': {
1236:                        int len = str.length();
1237:                        if (len != 8) {
1238:                            throw new ParseException();
1239:                        }
1240:                        int value = 0;
1241:                        for (int p = 3; p < 7; p++) {
1242:                            int ch = str.charAt(p);
1243:                            switch (ch) {
1244:                            case '0':
1245:                            case '1':
1246:                            case '2':
1247:                            case '3':
1248:                            case '4':
1249:                            case '5':
1250:                            case '6':
1251:                            case '7':
1252:                            case '8':
1253:                            case '9':
1254:                                value = (value << 4) + (ch - '0');
1255:                                break;
1256:                            case 'a':
1257:                            case 'A':
1258:                            case 'b':
1259:                            case 'B':
1260:                            case 'c':
1261:                            case 'C':
1262:                            case 'd':
1263:                            case 'D':
1264:                            case 'e':
1265:                            case 'E':
1266:                            case 'f':
1267:                            case 'F':
1268:                                value = (value << 4) + 10
1269:                                        + Character.toLowerCase((char) ch)
1270:                                        - 'a';
1271:                                break;
1272:                            default:
1273:                                throw new ParseException();
1274:                            }
1275:                        }
1276:                        return new Character((char) value);
1277:                    }
1278:                    default:
1279:                        throw new ParseException();
1280:                    }
1281:                } else {
1282:                    if (str.length() > 3) {
1283:                        throw new ParseException();
1284:                    }
1285:                    return new Character(str.charAt(1));
1286:                }
1287:            }
1288:
1289:            /**
1290:             * Creates an object from a number literal and a unit symbol
1291:             * 
1292:             * @param number
1293:             *            a number object
1294:             * @param numberString
1295:             *            a symbol of the number literal
1296:             * @param unit
1297:             *            a unit symbol
1298:             * @param context
1299:             *            a context in which the quantity is created
1300:             */
1301:            public static Object quantity(Number number, String numberString,
1302:                    String unit, Context context) {
1303:                Hashtable units = context.unitTable;
1304:                if (units != null) {
1305:                    QuantityFactory factory = (QuantityFactory) units.get(unit);
1306:                    if (factory != null) {
1307:                        return factory.make(number, unit);
1308:                    }
1309:                }
1310:                if ("f".equals(unit) || "F".equals(unit)) {
1311:                    return new Float(number.floatValue());
1312:                } else if ("d".equals(unit) || "D".equals(unit)) {
1313:                    return new Double(number.doubleValue());
1314:                } else if ("l".equals(unit) || "L".equals(unit)) {
1315:                    return new Long(number.longValue());
1316:                } else if ("b".equals(unit) || "B".equals(unit)) {
1317:                    return decimalNumber(numberString, 10);
1318:                }
1319:                throw new PnutsException("unitName.notDefined",
1320:                        new Object[] { unit }, context);
1321:            }
1322:
1323:            /**
1324:             * This method is called by the syntax "primitiveType(object)" and
1325:             * "(primitiveType)object"
1326:             * 
1327:             * @param context
1328:             *            the context
1329:             * @param primitiveType
1330:             *            a primitive type
1331:             * @param param
1332:             *            the parameter
1333:             * @param flag
1334:             *            string <->number conversion
1335:             */
1336:            public static Object primitive(Context context,
1337:                    Class primitiveType, Object param, boolean flag) {
1338:                return primitive(primitiveType, param, flag, 10);
1339:            }
1340:
1341:            static Object primitive(Class primitiveType, Object param,
1342:                    boolean flag, int radix) {
1343:                if (primitiveType == int.class) {
1344:                    if (param instanceof  Byte) {
1345:                        byte b = ((Byte) param).byteValue();
1346:                        return new Integer((int) b);
1347:                    } else if (param instanceof  Character) {
1348:                        return new Integer((int) ((Character) param)
1349:                                .charValue());
1350:                    } else if (param instanceof  Number) {
1351:                        return new Integer(((Number) param).intValue());
1352:                    } else if (flag) {
1353:                        if (param == null) {
1354:                            return null;
1355:                        } else {
1356:                            return new Integer(Integer.parseInt(param
1357:                                    .toString().trim(), radix));
1358:                        }
1359:                    }
1360:                } else if (primitiveType == byte.class) {
1361:                    if (param instanceof  Character) {
1362:                        return new Byte((byte) ((Character) param).charValue());
1363:                    } else if (param instanceof  Number) {
1364:                        return new Byte(((Number) param).byteValue());
1365:                    } else if (flag) {
1366:                        if (param == null) {
1367:                            return null;
1368:                        } else {
1369:                            return new Byte(Byte.parseByte(param.toString()
1370:                                    .trim(), radix));
1371:                        }
1372:                    }
1373:                } else if (primitiveType == char.class) {
1374:                    if (param instanceof  Number) {
1375:                        int i = ((Number) param).intValue();
1376:                        return new Character((char) (i & 0xffff));
1377:                    } else if (param instanceof  Character) {
1378:                        return param;
1379:                    }
1380:                } else if (primitiveType == long.class) {
1381:                    if (param instanceof  Number) {
1382:                        return new Long(((Number) param).longValue());
1383:                    } else if (flag) {
1384:                        if (param == null) {
1385:                            return null;
1386:                        } else {
1387:                            return new Long(Long.parseLong(param.toString()
1388:                                    .trim(), radix));
1389:                        }
1390:                    }
1391:                } else if (primitiveType == short.class) {
1392:                    if (param instanceof  Character) {
1393:                        return new Short((short) ((Character) param)
1394:                                .charValue());
1395:                    } else if (param instanceof  Number) {
1396:                        return new Short(((Number) param).shortValue());
1397:                    } else if (flag) {
1398:                        if (param == null) {
1399:                            return null;
1400:                        } else {
1401:                            return new Short(Short.parseShort(param.toString()
1402:                                    .trim(), radix));
1403:                        }
1404:                    }
1405:                } else if (primitiveType == double.class) {
1406:                    if (param instanceof  Number) {
1407:                        return new Double(((Number) param).doubleValue());
1408:                    } else if (flag) {
1409:                        if (param == null) {
1410:                            return null;
1411:                        } else {
1412:                            return Double.valueOf(param.toString().trim());
1413:                        }
1414:                    }
1415:                } else if (primitiveType == float.class) {
1416:                    if (param instanceof  Number) {
1417:                        return new Float(((Number) param).floatValue());
1418:                    } else if (flag) {
1419:                        if (param == null) {
1420:                            return null;
1421:                        } else {
1422:                            return Float.valueOf(param.toString().trim());
1423:                        }
1424:                    }
1425:                } else if (primitiveType == boolean.class) {
1426:                    if (flag) {
1427:                        return toBoolean(param);
1428:                    } else {
1429:                        if (param instanceof  Boolean) {
1430:                            return param;
1431:                        } else if (param == null) {
1432:                            return Boolean.FALSE;
1433:                        }
1434:                    }
1435:                }
1436:                throw new ClassCastException("(" + primitiveType.getName()
1437:                        + ")" + Pnuts.format(param));
1438:            }
1439:
1440:            /**
1441:             * Convert a given object to a boolean value
1442:             */
1443:            public static Boolean toBoolean(Object param) {
1444:                if (param instanceof  Boolean) {
1445:                    return (Boolean) param;
1446:                } else if (param == null) {
1447:                    return Boolean.FALSE;
1448:                } else if (param instanceof  Double) {
1449:                    double value = ((Double) param).doubleValue();
1450:                    return Boolean
1451:                            .valueOf(value != 0.0 && !Double.isNaN(value));
1452:                } else if (param instanceof  Float) {
1453:                    float value = ((Float) param).floatValue();
1454:                    return Boolean
1455:                            .valueOf(value != 0.0f && !Float.isNaN(value));
1456:                } else if (param instanceof  Number) {
1457:                    return eq(ZERO, param) ? Boolean.FALSE : Boolean.TRUE;
1458:                } else if (param instanceof  String) {
1459:                    return ((String) param).length() > 0 ? Boolean.TRUE
1460:                            : Boolean.FALSE;
1461:                } else {
1462:                    return Boolean.TRUE;
1463:                }
1464:            }
1465:
1466:            /**
1467:             * This method is called by the syntax "(Class)object"
1468:             * 
1469:             * @param context
1470:             *            the context
1471:             * @param type
1472:             *            the type
1473:             * @param flag
1474:             *            object_array <->primitive_array conversion
1475:             */
1476:            public static Object cast(Context context, Class type,
1477:                    Object object, boolean flag) {
1478:                if (type.isPrimitive()) {
1479:                    return primitive(context, type, object, false);
1480:                }
1481:                if (object == null) {
1482:                    return null;
1483:                } else if (type.isInstance(object)) {
1484:                    return object;
1485:                } else if (type.isArray()) {
1486:                    if (flag) {
1487:                        try {
1488:                            return transform(type, object, context);
1489:                        } catch (IllegalArgumentException e) {
1490:                            throw new ClassCastException("("
1491:                                    + getClassName(type) + ")"
1492:                                    + Pnuts.format(object));
1493:                        }
1494:                    } else {
1495:                        return object;
1496:                    }
1497:                }
1498:                throw new ClassCastException("(" + getClassName(type) + ")"
1499:                        + Pnuts.format(object));
1500:            }
1501:
1502:            /**
1503:             * Check if the parameter is an array
1504:             * 
1505:             * @param obj
1506:             *            the object to be checked
1507:             * @return true if the obj is an array, false otherwise.
1508:             */
1509:            public final static boolean isArray(Object obj) {
1510:                return (obj instanceof  Object[] || obj instanceof  int[]
1511:                        || obj instanceof  char[] || obj instanceof  boolean[]
1512:                        || obj instanceof  byte[] || obj instanceof  double[]
1513:                        || obj instanceof  long[] || obj instanceof  short[] || obj instanceof  float[]);
1514:            }
1515:
1516:            /**
1517:             * Gets an array's length
1518:             * 
1519:             * @param array
1520:             *            the array
1521:             * @return the length
1522:             */
1523:            public final static int getArrayLength(Object array) {
1524:                if (array instanceof  Object[]) {
1525:                    return ((Object[]) array).length;
1526:                } else if (array instanceof  int[]) {
1527:                    return ((int[]) array).length;
1528:                } else if (array instanceof  byte[]) {
1529:                    return ((byte[]) array).length;
1530:                } else if (array instanceof  char[]) {
1531:                    return ((char[]) array).length;
1532:                } else if (array instanceof  float[]) {
1533:                    return ((float[]) array).length;
1534:                } else if (array instanceof  double[]) {
1535:                    return ((double[]) array).length;
1536:                } else if (array instanceof  boolean[]) {
1537:                    return ((boolean[]) array).length;
1538:                } else if (array instanceof  long[]) {
1539:                    return ((long[]) array).length;
1540:                } else if (array instanceof  short[]) {
1541:                    return ((short[]) array).length;
1542:                } else {
1543:                    throw new IllegalArgumentException(String.valueOf(array));
1544:                }
1545:            }
1546:
1547:            /**
1548:             * Range expression 'target[idx1..idx2]'.
1549:             * 
1550:             * @return the intersection of the whole range of the target object and the
1551:             *         range [idx1..idx2]. This method never throw
1552:             *         ArrayIndexOutOfBoundsException.
1553:             */
1554:            public static Object getRange(Object target, Object idx1,
1555:                    Object idx2, Context context) {
1556:                return context.config.getRange(context, target, idx1, idx2);
1557:            }
1558:
1559:            /**
1560:             * This method is called by the syntax "id[from..to] = sth"
1561:             */
1562:            public static Object setRange(Object target, Object idx1,
1563:                    Object idx2, Object expr, Context context) {
1564:                return context.config.setRange(context, target, idx1, idx2,
1565:                        expr);
1566:            }
1567:
1568:            public static String replaceChar(String str, Number n, Object expr) {
1569:                int len = str.length();
1570:                int idx = ((Number) n).intValue();
1571:                if (idx < 0 && idx >= -len) {
1572:                    idx += len;
1573:                }
1574:                StringBuffer sbuf = new StringBuffer(str);
1575:                if (expr instanceof  Character) {
1576:                    sbuf.setCharAt(idx, ((Character) expr).charValue());
1577:                } else if (expr instanceof  String) {
1578:                    sbuf.replace(idx, idx + 1, expr.toString());
1579:                } else if (expr instanceof  char[]) {
1580:                    sbuf.replace(idx, idx + 1, new String((char[]) expr));
1581:                } else {
1582:                    throw new IllegalArgumentException(String.valueOf(expr));
1583:                }
1584:                return sbuf.toString();
1585:            }
1586:
1587:            protected static void checkException(Context context,
1588:                    Throwable throwable) {
1589:                if (throwable instanceof  ParseException) {
1590:                    context.beginLine = ((ParseException) throwable)
1591:                            .getErrorLine();
1592:                }
1593:                StackFrame stackFrame = context.stackFrame;
1594:                if (stackFrame != null) {
1595:                    StackFrame frame = stackFrame;
1596:                    if (stackFrame.parent != null) {
1597:                        NamedValue b = frame
1598:                                .lookup(Context.exceptionHandlerTableSymbol);
1599:                        if (b != null) {
1600:                            checkException(context, throwable, (TypeMap) b
1601:                                    .get());
1602:                            return;
1603:                        }
1604:                    }
1605:                }
1606:                TypeMap tmap = (TypeMap) context
1607:                        .resolveSymbol(Context.exceptionHandlerTableSymbol);
1608:                if (tmap != null) {
1609:                    checkException(context, throwable, tmap);
1610:                    return;
1611:                }
1612:                if (throwable instanceof  Escape) {
1613:                    throw (Escape) throwable;
1614:                } else if (throwable instanceof  PnutsException) {
1615:                    throw (PnutsException) throwable;
1616:                } else {
1617:                    throw new PnutsException(throwable, context);
1618:                }
1619:            }
1620:
1621:            /**
1622:             * Check if any exception handler is registered to the specified exception.
1623:             * If any an exception handler is executed. If not, the exception is thrown.
1624:             * 
1625:             * @param context
1626:             *            the Context in which the exception is checked
1627:             * @param throwable
1628:             *            the exception
1629:             * @param tmap
1630:             *            the exception handler table
1631:             */
1632:            protected static void checkException(Context context,
1633:                    Throwable throwable, TypeMap tmap) {
1634:                if (DEBUG) {
1635:                    System.out.println("checkException " + throwable + ", "
1636:                            + tmap);
1637:                }
1638:                Throwable e = throwable;
1639:                if (e instanceof  PnutsException) {
1640:                    throwable = ((PnutsException) e).getThrowable();
1641:                }
1642:                if (throwable instanceof  Escape) {
1643:                    if (DEBUG) {
1644:                        System.out.println(throwable);
1645:                    }
1646:                    throw (Escape) throwable;
1647:                }
1648:                if (throwable instanceof  ThreadDeath) {
1649:                    throw (ThreadDeath) throwable;
1650:                }
1651:                PnutsFunction f = null;
1652:                while (tmap != null) {
1653:                    Class type = tmap.type;
1654:                    if (type == null || type.isInstance(throwable)) {
1655:                        f = (PnutsFunction) tmap.value;
1656:                        break;
1657:                    }
1658:                    tmap = tmap.next;
1659:                }
1660:                if (f == null) {
1661:                    if (e instanceof  PnutsException) {
1662:                        throw (PnutsException) e;
1663:                    } else {
1664:                        throw new PnutsException(throwable, context);
1665:                    }
1666:                } else {
1667:                    Object ret = f.exec(new Object[] { throwable }, context);
1668:                    PrintWriter pw = context.getWriter();
1669:                    if (pw != null) {
1670:                        pw.flush();
1671:                    }
1672:                    throw new Jump(ret);
1673:                }
1674:            }
1675:
1676:            /**
1677:             * This method is called when catch() function is called in a
1678:             * package(non-local) scope
1679:             * 
1680:             * @param type
1681:             *            the exception type of which an exception handler is registered
1682:             * @param func
1683:             *            the function to be registered as an exception handler
1684:             * @param context
1685:             *            the context in which the exception handler is registered
1686:             */
1687:            protected static void catchException(Class type,
1688:                    PnutsFunction func, Context context) {
1689:                if (DEBUG) {
1690:                    System.out.println("catchException " + type.getName()
1691:                            + ": " + func.unparse(1));
1692:                }
1693:                Package pkg = context.getCurrentPackage();
1694:                TypeMap typemap = null;
1695:                if (type != Throwable.class) {
1696:                    typemap = (TypeMap) pkg.get(
1697:                            Context.exceptionHandlerTableSymbol, context);
1698:                }
1699:                pkg.set(Context.exceptionHandlerTableSymbol, new TypeMap(type,
1700:                        func, typemap), context);
1701:            }
1702:
1703:            public static void throwException(Object arg, Context context) {
1704:                if (arg instanceof  Throwable) {
1705:                    throw new PnutsException((Throwable) arg, context);
1706:                } else {
1707:                    throw new PnutsException(String.valueOf(arg));
1708:                }
1709:            }
1710:
1711:            public static void setExitHook(Context context,
1712:                    final PnutsFunction func) {
1713:                context.setExitHook(new Executable() {
1714:                    public Object run(Context ctx) {
1715:                        return func.call(new Object[] {}, ctx);
1716:                    }
1717:                });
1718:            }
1719:
1720:            /**
1721:             * This method is called by the syntax "target[key]"
1722:             */
1723:            public static Object getElement(Object target, Object key,
1724:                    Context context) {
1725:                return context.config.getElement(context, target, key);
1726:            }
1727:
1728:            public static Object getElementAt(Object target, int idx,
1729:                    Context context) {
1730:                try {
1731:                    if (target == null) {
1732:                        return null;
1733:                    } else {
1734:                        return context.config.getElement(context, target,
1735:                                new Integer(idx));
1736:                    }
1737:                } catch (IndexOutOfBoundsException e) {
1738:                    return null;
1739:                }
1740:            }
1741:
1742:            /**
1743:             * This method is called by the syntax "target[key] = value"
1744:             */
1745:            public static void setElement(Object target, Object key,
1746:                    Object value, Context context) {
1747:                context.config.setElement(context, target, key, value);
1748:            }
1749:
1750:            /*
1751:             * Converts an object to Enumeration This method is called by foreach
1752:             * statements.
1753:             * 
1754:             * @param target the target object to be converted to an Enumeration @param
1755:             * context the context in which the target object is converted to an
1756:             * Enumeration @return an Enumeration object converted from the target
1757:             * object. null if the target object could not be converted to an
1758:             * Enumeration.
1759:             */
1760:            public static Enumeration toEnumeration(Object target,
1761:                    Context context) {
1762:                return context.config.toEnumeration(target);
1763:            }
1764:
1765:            /**
1766:             * Call a function
1767:             * 
1768:             * @param context
1769:             *            the context in which the function is called
1770:             * @param func
1771:             *            the function to be called
1772:             * @param args
1773:             *            the arguments
1774:             */
1775:            protected final static Object callFunction(Context context,
1776:                    PnutsFunction func, Object[] args) {
1777:                return func.exec(args, context);
1778:            }
1779:
1780:            /**
1781:             * This method is called by the syntax "funcOrClass(args...)"
1782:             */
1783:            public final static Object call(Context context, Object target,
1784:                    Object[] args, Class[] casts) {
1785:                if (target instanceof  PnutsFunction) {
1786:                    return ((PnutsFunction) target).exec(args, context);
1787:                } else if (target instanceof  Class) {
1788:                    Class c = (Class) target;
1789:                    if (c.isPrimitive()) {
1790:                        try {
1791:                            int nargs = args.length;
1792:                            switch (nargs) {
1793:                            case 1:
1794:                                return primitive(context, c, args[0], true);
1795:                            case 2:
1796:                                int radix = ((Integer) args[1]).intValue();
1797:                                return primitive(c, args[0], true, radix);
1798:                            default:
1799:                                throw new IllegalArgumentException(Pnuts
1800:                                        .format(args));
1801:                            }
1802:                        } catch (NumberFormatException e) {
1803:                            return null;
1804:                        }
1805:                    } else if (c.isArray()) {
1806:                        return cast(context, c, args[0], true);
1807:                    } else {
1808:                        return context.config.callConstructor(context, c, args,
1809:                                casts);
1810:                    }
1811:                } else if (target instanceof  Callable) {
1812:                    return ((Callable) target).call(args, context);
1813:                }
1814:                throw new PnutsException("funcOrType.expected",
1815:                        new Object[] { Pnuts.format(target) }, context);
1816:            }
1817:
1818:            public final static Object call(Context context, Object target,
1819:                    Object[] args, Class[] casts, int line, int column) {
1820:                Object ret;
1821:                if (target instanceof  PnutsFunction) {
1822:                    Function caller = context.frame;
1823:                    PnutsFunction f = (PnutsFunction) target;
1824:                    try {
1825:                        ret = f.exec(args, context);
1826:                    } catch (PnutsException p) {
1827:                        if (caller != null) {
1828:                            p.backtrace(new PnutsException.TraceInfo(f.name,
1829:                                    args, caller.file, line, column));
1830:                        } else {
1831:                            p.backtrace(new PnutsException.TraceInfo(f.name,
1832:                                    args, null, line, column));
1833:                        }
1834:                        throw p;
1835:                    }
1836:                } else if (target instanceof  Class) {
1837:                    Class c = (Class) target;
1838:                    if (c.isPrimitive()) {
1839:                        try {
1840:                            int nargs = args.length;
1841:                            switch (nargs) {
1842:                            case 1:
1843:                                ret = primitive(context, c, args[0], true);
1844:                                break;
1845:                            case 2:
1846:                                int radix = ((Integer) args[1]).intValue();
1847:                                ret = primitive(c, args[0], true, radix);
1848:                                break;
1849:                            default:
1850:                                throw new IllegalArgumentException(Pnuts
1851:                                        .format(args));
1852:                            }
1853:                        } catch (NumberFormatException e) {
1854:                            context.updateLine(null, line, column);
1855:                            return null;
1856:                        }
1857:                    } else if (c.isArray()) {
1858:                        ret = cast(context, c, args[0], true);
1859:                    } else {
1860:                        ret = context.config.callConstructor(context, c, args,
1861:                                casts);
1862:                    }
1863:                } else if (target instanceof  Callable) {
1864:                    return ((Callable) target).call(args, context);
1865:                } else {
1866:                    Callable c = context.config.toCallable(target);
1867:                    if (c != null) {
1868:                        return c.call(args, context);
1869:                    } else {
1870:                        throw new PnutsException("funcOrType.expected",
1871:                                new Object[] { Pnuts.format(target) }, context);
1872:                    }
1873:                }
1874:                context.updateLine(null, line, column);
1875:                return ret;
1876:            }
1877:
1878:            protected static Object newInstance(Context context, Class c,
1879:                    Object[] args, Class[] casts) {
1880:                return context.config.callConstructor(context, c, args, casts);
1881:            }
1882:
1883:            protected static Object makeArray(Object[] parameters,
1884:                    Context context) {
1885:                return context.config.makeArray(parameters, context);
1886:            }
1887:
1888:            protected static Map createMap(int size, Context context) {
1889:                return context.config.createMap(size, context);
1890:            }
1891:
1892:            protected static List createList(Context context) {
1893:                return context.config.createList();
1894:            }
1895:
1896:            protected static void jump(Object v) {
1897:                throw new Jump(v);
1898:            }
1899:
1900:            protected static void escape(Object v) {
1901:                throw new Escape(v);
1902:            }
1903:
1904:            /**
1905:             * Set line number information for error reporting
1906:             *
1907:             * @deprecated
1908:             */
1909:            protected static void setLine(Context context, int beginLine,
1910:                    int beginColumn) {
1911:                context.updateLine(null, beginLine, beginColumn);
1912:            }
1913:
1914:            public static void setLine(Context context, int line) {
1915:                context.updateLine(line);
1916:            }
1917:
1918:            protected static int getBeginLine(Context context) {
1919:                return context.beginLine;
1920:            }
1921:
1922:            protected static int getBeginColumn(Context context) {
1923:                return context.beginColumn;
1924:            }
1925:
1926:            protected static int getEndLine(Context context) {
1927:                return context.endLine;
1928:            }
1929:
1930:            protected static Function getFunction(PnutsFunction pf, int nargs) {
1931:                return pf.get(nargs);
1932:            }
1933:
1934:            protected static Enumeration getFunctions(PnutsFunction pf) {
1935:                return pf.elements();
1936:            }
1937:
1938:            protected static Runtime getRuntime(Context context) {
1939:                return context.runtime;
1940:            }
1941:
1942:            protected static Object getScriptSource(Context context) {
1943:                return context.getScriptSource();
1944:            }
1945:
1946:            protected static Function getFunction(Context context) {
1947:                return context.frame;
1948:            }
1949:
1950:            protected static void setPackage(Package pkg, Context context) {
1951:                pkg.init(context);
1952:            }
1953:
1954:            private static char[] hexDigit = { '0', '1', '2', '3', '4', '5',
1955:                    '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
1956:
1957:            private final static int DEFAULT_FORMAT_MAX_LENGTH = 512;
1958:
1959:            /**
1960:             * Get the String representation of the specified object.
1961:             * 
1962:             * @param object
1963:             *            the target object.
1964:             * @param maxArrayLength
1965:             *            When the target object is an array and maxArrayLength is
1966:             *            greater than zero, only the first maxArrayLength elements are
1967:             *            printed and the rest of the elements are omitted as "...".
1968:             */
1969:            public static String format(Object object, int maxArrayLength) {
1970:                return format(object, maxArrayLength, DEFAULT_FORMAT_MAX_LENGTH);
1971:            }
1972:
1973:            private final static char[] defaultParen = { '[', ']' };
1974:
1975:            public static String format(Object object, int maxArrayLength,
1976:                    int maxFormatSize) {
1977:                return format(object, maxArrayLength, maxFormatSize,
1978:                        defaultParen);
1979:            }
1980:
1981:            public static String format(Object object, int maxArrayLength,
1982:                    int maxFormatSize, char[] paren) {
1983:                StringBuffer sb = new StringBuffer();
1984:                try {
1985:                    format(object, maxArrayLength, maxFormatSize, paren,
1986:                            new HashSet(), sb);
1987:                } catch (TooLongFormat toolong) {
1988:                    sb.append("....");
1989:                }
1990:                return sb.toString();
1991:            }
1992:
1993:            static class TooLongFormat extends RuntimeException {
1994:            }
1995:
1996:            static void format(Object object, int maxArrayLength,
1997:                    int maxFormatSize, char[] paren, Set formattedObjects,
1998:                    StringBuffer sb) {
1999:                if (maxFormatSize < sb.length()) {
2000:                    throw new TooLongFormat();
2001:                }
2002:                if (object == null) {
2003:                    sb.append("null");
2004:                    return;
2005:                } else if (!(isArray(object))) {
2006:                    if (object instanceof  String) {
2007:                        String str = (String) object;
2008:                        int len = str.length();
2009:                        sb.append('"');
2010:                        for (int i = 0; i < len; i++) {
2011:                            char ch = str.charAt(i);
2012:                            switch (ch) {
2013:                            case '\\':
2014:                                sb.append("\\\\");
2015:                                break;
2016:                            case '\b':
2017:                                sb.append("\\b");
2018:                                break;
2019:                            case '\f':
2020:                                sb.append("\\f");
2021:                                break;
2022:                            case '\t':
2023:                                sb.append("\\t");
2024:                                break;
2025:                            case '\n':
2026:                                sb.append("\\n");
2027:                                break;
2028:                            case '\r':
2029:                                sb.append("\\r");
2030:                                break;
2031:                            case '"':
2032:                                sb.append("\\\"");
2033:                                break;
2034:                            default:
2035:                                char[] cbuf = new char[1];
2036:                                cbuf[0] = ch;
2037:                                byte[] conv = new String(cbuf).getBytes();
2038:                                if (ch == '?'
2039:                                        || !Character.isISOControl(ch)
2040:                                        && !(conv.length == 1 && conv[0] == (byte) '?')) {
2041:                                    sb.append(ch);
2042:                                } else {
2043:                                    sb.append("\\u"
2044:                                            + hexDigit[(ch >> 12) & 0xF]
2045:                                            + hexDigit[(ch >> 8) & 0xF]
2046:                                            + hexDigit[(ch >> 4) & 0xF]
2047:                                            + hexDigit[(ch >> 0) & 0xF]);
2048:                                }
2049:                                break;
2050:                            }
2051:                        }
2052:                        sb.append('"');
2053:                        return;
2054:                    } else if (object instanceof  Character) {
2055:                        String s;
2056:                        char ch = ((Character) object).charValue();
2057:                        switch (ch) {
2058:                        case '\\':
2059:                            s = "'\\'";
2060:                        case '\b':
2061:                            s = "'\\b'";
2062:                        case '\f':
2063:                            s = "'\\f'";
2064:                        case '\t':
2065:                            s = "'\\t'";
2066:                        case '\n':
2067:                            s = "'\\n'";
2068:                        case '\r':
2069:                            s = "'\\r'";
2070:                        case '\'':
2071:                            s = "'\\''";
2072:                        case '?':
2073:                            s = "'?'";
2074:                            sb.append(s);
2075:                            return;
2076:                        default:
2077:                            char[] buf = new char[1];
2078:                            buf[0] = ch;
2079:                            byte[] conv = new String(buf).getBytes();
2080:                            if (!Character.isISOControl(ch)
2081:                                    && !(conv.length == 1 && conv[0] == (byte) '?')) {
2082:                                sb.append('\'');
2083:                                sb.append(ch);
2084:                                sb.append('\'');
2085:                                return;
2086:                            }
2087:                            sb.append("'\\u" + hexDigit[(ch >> 12) & 0xF]
2088:                                    + hexDigit[(ch >> 8) & 0xF]
2089:                                    + hexDigit[(ch >> 4) & 0xF]
2090:                                    + hexDigit[(ch >> 0) & 0xF] + "'");
2091:                            return;
2092:                        }
2093:                    } else if (object instanceof  Class) {
2094:                        Class c = (Class) object;
2095:                        String suffix = null;
2096:                        if (c.isInterface()) {
2097:                            suffix = " interface";
2098:                        } else if (c.isPrimitive()) {
2099:                            suffix = " type";
2100:                        } else {
2101:                            suffix = " class";
2102:                        }
2103:                        sb.append(getClassName(c) + suffix);
2104:                        return;
2105:                    } else if (object instanceof  Byte) {
2106:                        byte value = ((Byte) object).byteValue();
2107:                        sb.append("#" + hexDigit[(value >> 4) & 0x0f]
2108:                                + hexDigit[value & 0x0f]);
2109:                        return;
2110:                    } else if (object instanceof  Float) {
2111:                        sb.append(object.toString() + "f");
2112:                        return;
2113:                    } else if (object instanceof  Calendar) {
2114:                        Calendar cal = (Calendar) object;
2115:                        DateFormat f = DateFormat.getDateTimeInstance();
2116:                        f.setTimeZone(cal.getTimeZone());
2117:                        sb.append(f.format(cal.getTime()));
2118:                        return;
2119:                    } else {
2120:                        sb.append(object.toString());
2121:                        return;
2122:                    }
2123:                }
2124:                int length = getArrayLength(object);
2125:                int last = length;
2126:                sb.append(paren[0]);
2127:
2128:                if (length > 0) {
2129:                    Object obj = Array.get(object, 0);
2130:                    if (obj != object) {
2131:                        formatElement(obj, maxArrayLength, maxFormatSize,
2132:                                paren, formattedObjects, sb);
2133:                    } else {
2134:                        sb.append(String.valueOf(obj));
2135:                    }
2136:                }
2137:                if (maxArrayLength > 0 && maxArrayLength < length) {
2138:                    last = maxArrayLength;
2139:                }
2140:                for (int j = 1; j < last; j++) {
2141:                    Object obj = Array.get(object, j);
2142:                    sb.append(", ");
2143:                    if (obj != object) {
2144:                        formatElement(obj, maxArrayLength, maxFormatSize,
2145:                                paren, formattedObjects, sb);
2146:                    } else {
2147:                        sb.append(String.valueOf(obj));
2148:                    }
2149:                }
2150:                if (maxArrayLength > 0 && maxArrayLength < length) {
2151:                    sb.append(", ...");
2152:                }
2153:                sb.append(paren[1]);
2154:            }
2155:
2156:            static void formatElement(Object obj, int maxArrayLength,
2157:                    int maxFormatSize, char[] paren, Set formattedObjects,
2158:                    StringBuffer sb) {
2159:                if (formattedObjects.contains(obj)) {
2160:                    if (obj == null) {
2161:                        sb.append("null");
2162:                    } else if (!(obj instanceof  Object[])) {
2163:                        sb.append(obj.toString());
2164:                    } else {
2165:                        sb.append(obj.getClass().getName() + "@"
2166:                                + obj.hashCode());
2167:                    }
2168:                } else {
2169:                    formattedObjects.add(obj);
2170:                    format(obj, maxArrayLength, maxFormatSize, paren,
2171:                            formattedObjects, sb);
2172:                    formattedObjects.remove(obj);
2173:                }
2174:            }
2175:
2176:            static String getClassName(Class cls) {
2177:                if (cls.isArray()) {
2178:                    StringBuffer buf = new StringBuffer();
2179:                    for (; cls.isArray(); cls = cls.getComponentType()) {
2180:                        buf.append("[]");
2181:                    }
2182:                    buf.insert(0, cls.getName());
2183:                    return buf.toString();
2184:                } else {
2185:                    return cls.getName();
2186:                }
2187:            }
2188:
2189:            /**
2190:             * Add 1 to an object (integer)
2191:             */
2192:            public final static Object add1(Object n) {
2193:                return UnaryOperator.Add1.instance.operateOn(n);
2194:            }
2195:
2196:            protected final static Object add1(Object n, Context context) {
2197:                return context._add1.operateOn(n);
2198:            }
2199:
2200:            /**
2201:             * Subtracts 1 from a object (integer)
2202:             */
2203:            public final static Object subtract1(Object n) {
2204:                return UnaryOperator.Subtract1.instance.operateOn(n);
2205:            }
2206:
2207:            protected final static Object subtract1(Object n, Context context) {
2208:                return context._subtract1.operateOn(n);
2209:            }
2210:
2211:            /**
2212:             * Negates an number
2213:             */
2214:            public final static Object negate(Object n) {
2215:                return UnaryOperator.Negate.instance.operateOn(n);
2216:            }
2217:
2218:            protected final static Object negate(Object n, Context context) {
2219:                return context._negate.operateOn(n);
2220:            }
2221:
2222:            public final static Object not(Object n) {
2223:                return UnaryOperator.Not.instance.operateOn(n);
2224:            }
2225:
2226:            protected final static Object not(Object n, Context context) {
2227:                return context._not.operateOn(n);
2228:            }
2229:
2230:            /**
2231:             * + operation
2232:             */
2233:            public final static Object add(Object n1, Object n2) {
2234:                return BinaryOperator.Add.instance.operateOn(n1, n2);
2235:            }
2236:
2237:            protected final static Object add(Object n1, Object n2,
2238:                    Context context) {
2239:                return context._add.operateOn(n1, n2);
2240:            }
2241:
2242:            /**
2243:             * - operation
2244:             */
2245:            public final static Object subtract(Object n1, Object n2) {
2246:                return BinaryOperator.Subtract.instance.operateOn(n1, n2);
2247:            }
2248:
2249:            protected final static Object subtract(Object n1, Object n2,
2250:                    Context context) {
2251:                return context._subtract.operateOn(n1, n2);
2252:            }
2253:
2254:            /**
2255:             * * operation
2256:             */
2257:            public final static Object multiply(Object n1, Object n2) {
2258:                return BinaryOperator.Multiply.instance.operateOn(n1, n2);
2259:            }
2260:
2261:            protected final static Object multiply(Object n1, Object n2,
2262:                    Context context) {
2263:                return context._multiply.operateOn(n1, n2);
2264:            }
2265:
2266:            /**
2267:             * / operation
2268:             */
2269:            public final static Object divide(Object n1, Object n2) {
2270:                return BinaryOperator.Divide.instance.operateOn(n1, n2);
2271:            }
2272:
2273:            protected final static Object divide(Object n1, Object n2,
2274:                    Context context) {
2275:                try {
2276:                    return context._divide.operateOn(n1, n2);
2277:                } catch (Exception e) {
2278:                    throw new PnutsException(e, context);
2279:                }
2280:            }
2281:
2282:            /**
2283:             * % operation
2284:             */
2285:            public final static Object mod(Object n1, Object n2) {
2286:                return BinaryOperator.Mod.instance.operateOn(n1, n2);
2287:            }
2288:
2289:            protected final static Object mod(Object n1, Object n2,
2290:                    Context context) {
2291:                return context._mod.operateOn(n1, n2);
2292:            }
2293:
2294:            /**
2295:             * < < operation
2296:             */
2297:            public final static Object shiftLeft(Object n1, Object n2) {
2298:                return BinaryOperator.ShiftLeft.instance.operateOn(n1, n2);
2299:            }
2300:
2301:            protected final static Object shiftLeft(Object n1, Object n2,
2302:                    Context context) {
2303:                return context._shiftLeft.operateOn(n1, n2);
2304:            }
2305:
2306:            /**
2307:             * >> operation
2308:             */
2309:            public final static Object shiftRight(Object n1, Object n2) {
2310:                return BinaryOperator.ShiftRight.instance.operateOn(n1, n2);
2311:            }
2312:
2313:            protected final static Object shiftRight(Object n1, Object n2,
2314:                    Context context) {
2315:                return context._shiftRight.operateOn(n1, n2);
2316:            }
2317:
2318:            /**
2319:             * >>> operation
2320:             */
2321:            public static Object shiftArithmetic(Object n1, Object n2) {
2322:                return BinaryOperator.ShiftArithmetic.instance
2323:                        .operateOn(n1, n2);
2324:            }
2325:
2326:            protected final static Object shiftArithmetic(Object n1, Object n2,
2327:                    Context context) {
2328:                return context._shiftArithmetic.operateOn(n1, n2);
2329:            }
2330:
2331:            /**
2332:             * | operation
2333:             */
2334:            public final static Object or(Object n1, Object n2) {
2335:                return BinaryOperator.Or.instance.operateOn(n1, n2);
2336:            }
2337:
2338:            protected final static Object or(Object n1, Object n2,
2339:                    Context context) {
2340:                return context._or.operateOn(n1, n2);
2341:            }
2342:
2343:            /**
2344:             * & operation
2345:             */
2346:            public final static Object and(Object n1, Object n2) {
2347:                return BinaryOperator.And.instance.operateOn(n1, n2);
2348:            }
2349:
2350:            protected final static Object and(Object n1, Object n2,
2351:                    Context context) {
2352:                return context._and.operateOn(n1, n2);
2353:            }
2354:
2355:            /**
2356:             * ^ operation
2357:             */
2358:            public final static Object xor(Object n1, Object n2) {
2359:                return BinaryOperator.Xor.instance.operateOn(n1, n2);
2360:            }
2361:
2362:            protected final static Object xor(Object n1, Object n2,
2363:                    Context context) {
2364:                return context._xor.operateOn(n1, n2);
2365:            }
2366:
2367:            /**
2368:             * < operation
2369:             */
2370:            public final static boolean lt(Object n1, Object n2) {
2371:                return BooleanOperator.LT.instance.operateOn(n1, n2);
2372:            }
2373:
2374:            protected final static boolean lt(Object n1, Object n2,
2375:                    Context context) {
2376:                return context._lt.operateOn(n1, n2);
2377:            }
2378:
2379:            /**
2380:             * > operation
2381:             */
2382:            public final static boolean gt(Object n1, Object n2) {
2383:                return BooleanOperator.GT.instance.operateOn(n1, n2);
2384:            }
2385:
2386:            protected final static boolean gt(Object n1, Object n2,
2387:                    Context context) {
2388:                return context._gt.operateOn(n1, n2);
2389:            }
2390:
2391:            /**
2392:             * >= operation
2393:             */
2394:            public final static boolean ge(Object n1, Object n2) {
2395:                return BooleanOperator.GE.instance.operateOn(n1, n2);
2396:            }
2397:
2398:            protected final static boolean ge(Object n1, Object n2,
2399:                    Context context) {
2400:                return context._ge.operateOn(n1, n2);
2401:            }
2402:
2403:            /**
2404:             * <= operation
2405:             */
2406:            public final static boolean le(Object n1, Object n2) {
2407:                return BooleanOperator.LE.instance.operateOn(n1, n2);
2408:            }
2409:
2410:            protected final static boolean le(Object n1, Object n2,
2411:                    Context context) {
2412:                return context._le.operateOn(n1, n2);
2413:            }
2414:
2415:            /**
2416:             * == operation
2417:             */
2418:            public final static boolean eq(Object n1, Object n2) {
2419:                return BooleanOperator.EQ.instance.operateOn(n1, n2);
2420:            }
2421:
2422:            protected final static boolean eq(Object n1, Object n2,
2423:                    Context context) {
2424:                return context._eq.operateOn(n1, n2);
2425:            }
2426:
2427:            /**
2428:             * != operation
2429:             */
2430:            public final static boolean ne(Object n1, Object n2) {
2431:                return !BooleanOperator.EQ.instance.operateOn(n1, n2);
2432:            }
2433:
2434:            protected final static boolean ne(Object n1, Object n2,
2435:                    Context context) {
2436:                return !context._eq.operateOn(n1, n2);
2437:            }
2438:
2439:            /**
2440:             * Compares n1 with n2
2441:             */
2442:            public final static int compareTo(Object n1, Object n2) {
2443:                if (gt(n1, n2)) {
2444:                    return 1;
2445:                } else if (lt(n1, n2)) {
2446:                    return -1;
2447:                } else {
2448:                    return 0;
2449:                }
2450:            }
2451:
2452:            protected final static int compareTo(Object n1, Object n2,
2453:                    Context context) {
2454:                if (gt(n1, n2, context)) {
2455:                    return 1;
2456:                } else if (lt(n1, n2, context)) {
2457:                    return -1;
2458:                } else {
2459:                    return 0;
2460:                }
2461:            }
2462:
2463:            /**
2464:             * Compare two objects
2465:             * 
2466:             * Elements of List and array are recursively compared.
2467:             */
2468:            public static int compareObjects(Object e1, Object e2) {
2469:                if (e1 == e2) {
2470:                    return 0;
2471:                }
2472:                if (e1 instanceof  List) {
2473:                    if (e2 instanceof  List) {
2474:                        return compareLists((List) e1, (List) e2);
2475:                    } else if (Runtime.isArray(e2)) {
2476:                        return compareListToArray((List) e1, e2);
2477:                    }
2478:                } else if (Runtime.isArray(e1)) {
2479:                    if (e2 instanceof  List) {
2480:                        return -compareListToArray((List) e2, e1);
2481:                    } else if (Runtime.isArray(e2)) {
2482:                        return compareArrays(e1, e2);
2483:                    }
2484:                }
2485:                if (e1 instanceof  Comparable) {
2486:                    return ((Comparable) e1).compareTo(e2);
2487:                } else if (e2 instanceof  Comparable) {
2488:                    return -((Comparable) e2).compareTo(e1);
2489:                } else {
2490:                    throw new IllegalArgumentException();
2491:                }
2492:            }
2493:
2494:            static int compareLists(List ol1, List ol2) {
2495:                int sz2 = ol2.size();
2496:                int sz1 = ol1.size();
2497:                int min = (sz2 > sz1) ? sz1 : sz2;
2498:                for (int i = 0; i < min; i++) {
2499:                    Object e1 = ol1.get(i);
2500:                    Object e2 = ol2.get(i);
2501:                    int c = compareObjects(e1, e2);
2502:                    if (c != 0) {
2503:                        return c;
2504:                    }
2505:                }
2506:                if (sz1 == sz2) {
2507:                    return 0;
2508:                } else {
2509:                    return (sz1 > sz2) ? 1 : -1;
2510:                }
2511:            }
2512:
2513:            static int compareListToArray(List ol, Object array) {
2514:                int len = Array.getLength(array);
2515:                int sz = ol.size();
2516:                int min = (len > sz) ? sz : len;
2517:                for (int i = 0; i < min; i++) {
2518:                    Object e1 = ol.get(i);
2519:                    Object e2 = Array.get(array, i);
2520:                    int c = compareObjects(e1, e2);
2521:                    if (c != 0) {
2522:                        return c;
2523:                    }
2524:                }
2525:                if (sz == len) {
2526:                    return 0;
2527:                } else {
2528:                    return (sz > len) ? 1 : -1;
2529:                }
2530:            }
2531:
2532:            static int compareArrays(Object a1, Object a2) {
2533:                int len = Array.getLength(a1);
2534:                int sz = Array.getLength(a2);
2535:                int min = (len > sz) ? sz : len;
2536:                for (int i = 0; i < min; i++) {
2537:                    Object e1 = Array.get(a1, i);
2538:                    Object e2 = Array.get(a2, i);
2539:                    int c = compareObjects(e1, e2);
2540:                    if (c != 0) {
2541:                        return c;
2542:                    }
2543:                }
2544:                if (sz == len) {
2545:                    return 0;
2546:                } else {
2547:                    return (sz > len) ? 1 : -1;
2548:                }
2549:            }
2550:
2551:            /**
2552:             * Returns a URL of a script
2553:             */
2554:            public static URL getScriptURL(String name, Context context) {
2555:                URL url = null;
2556:                //		try {
2557:                url = Pnuts.getResource(name, context);
2558:                if (url == null) {
2559:                    url = Pnuts.getResource("/" + name, context);
2560:                }
2561:                if (url == null)
2562:                    return null;
2563:                //			URLConnection conn = url.openConnection();
2564:                //			conn.connect();
2565:                /*
2566:                if (context.verbose) {
2567:                PrintWriter out = context.getTerminalWriter();
2568:                if (out != null) {
2569:                out.println("[loading " + url + "]");
2570:                out.flush();
2571:                }
2572:                }
2573:                 */
2574:
2575:                //		} catch (IOException ioe) {
2576:                //			return null;
2577:                //		}
2578:                return url;
2579:            }
2580:
2581:            /**
2582:             * This method is called by Pnuts.load() when the property
2583:             * "pnuts.compiled.script.prefix" is defined, to load pre-compiled scripts.
2584:             * 
2585:             * @param name
2586:             *            the script name
2587:             * @param context
2588:             *            the context in which the class is loaded.
2589:             * @return pnuts.lang.Runtime object if the class is found, otherwise null.
2590:             */
2591:            public static Executable getCompiledScript(String name,
2592:                    Context context) {
2593:                String prefix = Pnuts.getCompiledClassPrefix();
2594:                Object rt = null;
2595:                try {
2596:                    String cname = name.replace('/', '.').replace('-', '_');
2597:                    if (prefix != null) {
2598:                        cname = prefix + cname;
2599:                    }
2600:                    Class cls = Pnuts.loadClass(cname, context);
2601:                    rt = cls.newInstance();
2602:                    if (rt instanceof  Executable) {
2603:                        return (Executable) rt;
2604:                    }
2605:                } catch (ClassNotFoundException e0) { /* ignore */
2606:                } catch (InstantiationException e1) { /* ignore */
2607:                } catch (IllegalAccessException e2) { /* ignore */
2608:                }
2609:                return null;
2610:            }
2611:
2612:            /**
2613:             * Gets a URL from a File
2614:             * 
2615:             * @param file
2616:             *            the File object
2617:             * @return the resulting URL object
2618:             */
2619:            public static URL fileToURL(File file) throws IOException {
2620:                String path = new File(file.getCanonicalPath())
2621:                        .getAbsolutePath();
2622:                if (File.separatorChar != '/') {
2623:                    path = path.replace(File.separatorChar, '/');
2624:                }
2625:                if (!path.startsWith("/")) {
2626:                    path = "/" + path;
2627:                }
2628:                if (!path.endsWith("/") && file.isDirectory()) {
2629:                    path = path + "/";
2630:                }
2631:                return new URL("file", "", path);
2632:            }
2633:
2634:            /**
2635:             * Gets a Reader to read script files
2636:             * 
2637:             * If context.getScriptEncoding() is non-null, it would be used as the
2638:             * encoding. Otherwise, the platform encoding is used.
2639:             * 
2640:             * @param in
2641:             *            the input stream
2642:             * @param context
2643:             *            the executing context
2644:             * @return the resulting reader object
2645:             */
2646:            public static Reader getScriptReader(InputStream in, Context context) {
2647:                String encoding = context.encoding;
2648:                if (encoding == null) {
2649:                    return new InputStreamReader(in);
2650:                } else {
2651:                    try {
2652:                        return new InputStreamReader(in, encoding);
2653:                    } catch (UnsupportedEncodingException e) {
2654:                        throw new PnutsException(e, context);
2655:                    }
2656:                }
2657:            }
2658:
2659:            public static void printError(Throwable t, Context context) {
2660:                context.onError(t);
2661:                PrintWriter err = context.getErrorWriter();
2662:                if (err != null) {
2663:                    if (context.verbose) {
2664:                        t.printStackTrace(err);
2665:                    } else {
2666:                        err.println(t);
2667:                    }
2668:                    err.flush();
2669:                } else {
2670:                    t.printStackTrace();
2671:                }
2672:            }
2673:
2674:            protected static String getMessage(String bundleName, String key,
2675:                    Object a[]) {
2676:                try {
2677:                    ResourceBundle bundle = ResourceBundle
2678:                            .getBundle(bundleName);
2679:                    String fmt = bundle.getString(key);
2680:                    if (fmt == null) {
2681:                        return null;
2682:                    }
2683:                    return MessageFormat.format(fmt, a);
2684:                } catch (MissingResourceException e) {
2685:                    return bundleName + ":" + key + Runtime.format(a, 64);
2686:                }
2687:            }
2688:
2689:            static Number compress(Number n) {
2690:                if (n instanceof  BigInteger) {
2691:                    BigInteger b = (BigInteger) n;
2692:                    if (b.compareTo(BinaryOperator.maxLong) > 0
2693:                            || b.compareTo(BinaryOperator.minLong) < 0) {
2694:                        return n;
2695:                    } else {
2696:                        long l = b.longValue();
2697:                        if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) {
2698:                            return new Integer((int) l);
2699:                        } else {
2700:                            return new Long(l);
2701:                        }
2702:                    }
2703:                } else if (n instanceof  BigDecimal) {
2704:                    int j = 0;
2705:                    String f = n.toString();
2706:                    int p = f.indexOf((int) '.');
2707:                    if (p > 0) {
2708:                        char ca[] = f.toCharArray();
2709:                        for (int i = 0; i < ca.length - 2
2710:                                && i < ca.length - p - 2; i++) {
2711:                            if (ca[ca.length - i - 1] == '0') {
2712:                                j++;
2713:                            } else {
2714:                                break;
2715:                            }
2716:                        }
2717:                        f = f.substring(0, ca.length - j);
2718:                    }
2719:                    if (f.length() < 16) {
2720:                        return new Double(n.doubleValue());
2721:                    }
2722:                    if (j > 0) {
2723:                        return new BigDecimal(f);
2724:                    } else {
2725:                        return n;
2726:                    }
2727:                } else if (n instanceof  Long) {
2728:                    long l = ((Long) n).longValue();
2729:                    if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) {
2730:                        return new Integer((int) l);
2731:                    } else {
2732:                        return new Long(l);
2733:                    }
2734:                } else {
2735:                    return n;
2736:                }
2737:            }
2738:
2739:            static Number decimalNumber(String s, int radix) {
2740:                if (radix == 16 || radix == 8) {
2741:                    return new BigInteger(s, radix);
2742:                } else {
2743:                    return new BigDecimal(deNormalize(s));
2744:                }
2745:            }
2746:
2747:            private static String deNormalize(String fmt) {
2748:                int pt = fmt.indexOf((int) '.');
2749:                int exp = fmt.indexOf((int) 'E');
2750:                if (exp < 0) {
2751:                    return fmt;
2752:                }
2753:                int e = Integer.parseInt(fmt.substring(exp + 1));
2754:                int i = 0;
2755:                int k = 0;
2756:                char b[];
2757:                if (e < 0) {
2758:                    b = new char[exp - e];
2759:                    i = 0;
2760:                    if (fmt.charAt(k) == '-') {
2761:                        b[i++] = '-';
2762:                        k++;
2763:                    }
2764:                    b[i++] = '0';
2765:                    b[i++] = '.';
2766:                    for (int j = 0; j < -e - 1; j++) {
2767:                        b[i++] = '0';
2768:                    }
2769:                    b[i++] = fmt.charAt(k++);
2770:                    k++;
2771:                    for (int j = 0; j < exp - pt - 1; j++) {
2772:                        b[i++] = fmt.charAt(k++);
2773:                    }
2774:                } else {
2775:                    if (exp - pt - 1 > e) {
2776:                        b = new char[exp];
2777:                        i = 0;
2778:                        if (fmt.charAt(k) == '-') {
2779:                            b[i++] = '-';
2780:                            k++;
2781:                        }
2782:                        b[i++] = fmt.charAt(k++);
2783:                        k++;
2784:                        for (int j = 0; j < e; j++) {
2785:                            b[i++] = fmt.charAt(k++);
2786:                        }
2787:                        b[i++] = '.';
2788:                        for (int j = 0; j < exp - pt - 1 - e; j++) {
2789:                            b[i++] = fmt.charAt(k++);
2790:                        }
2791:                    } else {
2792:                        b = new char[exp - 1 + (e - (exp - pt - 1))];
2793:                        i = 0;
2794:                        if (fmt.charAt(k) == '-') {
2795:                            b[i++] = '-';
2796:                            k++;
2797:                        }
2798:                        b[i++] = fmt.charAt(k++);
2799:                        k++;
2800:                        for (int j = 0; j < exp - pt - 1; j++) {
2801:                            b[i++] = fmt.charAt(k++);
2802:                        }
2803:                        for (int j = 0; j < e - (exp - pt - 1); j++) {
2804:                            b[i++] = '0';
2805:                        }
2806:                    }
2807:                }
2808:                return new String(b);
2809:            }
2810:
2811:            static class AutoloadScript implements  AutoloadHook, Serializable {
2812:                String file;
2813:
2814:                ModuleList moduleList;
2815:
2816:                Package pkg;
2817:
2818:                String encoding;
2819:
2820:                Configuration config;
2821:
2822:                AutoloadScript(String file, Context context) {
2823:                    this .file = file.intern();
2824:                    this .pkg = context.rootPackage;
2825:                    this .moduleList = context.moduleList;
2826:                    this .encoding = context.encoding;
2827:                    this .config = context.config;
2828:                }
2829:
2830:                public synchronized void load(String name, Context context) {
2831:                    try {
2832:                        Context ctx = (Context) context.clone();
2833:                        ctx.moduleList = this .moduleList;
2834:                        ctx.setCurrentPackage(this .pkg);
2835:                        ctx.encoding = this .encoding;
2836:                        ctx.config = this .config;
2837:                        Pnuts.require(file, ctx);
2838:                    } catch (Escape esc) {
2839:                        throw esc;
2840:                    } catch (FileNotFoundException e) {
2841:                        throw new PnutsException(e, context);
2842:                    }
2843:                }
2844:            }
2845:
2846:            protected static class TypeMap {
2847:                Class type;
2848:
2849:                Object value;
2850:
2851:                TypeMap next;
2852:
2853:                public TypeMap(Class type, Object value, TypeMap next) {
2854:                    this .type = type;
2855:                    this .value = value;
2856:                    this .next = next;
2857:                }
2858:            }
2859:
2860:            protected static class Accessor {
2861:                protected Class beanClass;
2862:
2863:                protected Class stopClass;
2864:
2865:                HashMap readMethods;
2866:
2867:                HashMap writeMethods;
2868:
2869:                HashMap types;
2870:
2871:                protected Accessor(Class cls, Class stopClass) {
2872:                    init(cls, stopClass);
2873:                }
2874:
2875:                void init(Class cls, Class stopClass) {
2876:                    this .beanClass = cls;
2877:                    this .stopClass = stopClass;
2878:                    this .readMethods = new HashMap();
2879:                    this .writeMethods = new HashMap();
2880:                    this .types = new HashMap();
2881:
2882:                    ObjectDescFactory.getDefault().create(cls, stopClass)
2883:                            .handleProperties(new PropertyHandler() {
2884:                                public void handle(String propertyName,
2885:                                        Class type, Method readMethod,
2886:                                        Method writeMethod) {
2887:                                    if (readMethod != null) {
2888:                                        addReadMethod(propertyName, readMethod);
2889:                                    }
2890:                                    if (writeMethod != null) {
2891:                                        addWriteMethod(propertyName,
2892:                                                writeMethod);
2893:                                    }
2894:                                    types.put(propertyName, type);
2895:                                }
2896:                            });
2897:                }
2898:
2899:                public void addReadMethod(String name, Object m) {
2900:                    readMethods.put(name, m);
2901:                }
2902:
2903:                public void addWriteMethod(String name, Object m) {
2904:                    writeMethods.put(name, m);
2905:                }
2906:
2907:                public Object findReadMethod(String name) {
2908:                    return readMethods.get(name);
2909:                }
2910:
2911:                public Object findWriteMethod(String name) {
2912:                    return writeMethods.get(name);
2913:                }
2914:
2915:                public Class getType(String name) {
2916:                    return (Class) types.get(name);
2917:                }
2918:            }
2919:
2920:            public static String getProperty(final String key) {
2921:                Properties p = Pnuts.defaultSettings;
2922:                if (p != null) {
2923:                    String v = p.getProperty(key);
2924:                    if (v != null) {
2925:                        return v;
2926:                    }
2927:                }
2928:                try {
2929:                    String v = (String) AccessController
2930:                            .doPrivileged(new PrivilegedAction() {
2931:                                public Object run() {
2932:                                    return System.getProperty(key);
2933:                                }
2934:                            });
2935:                    if (v != null) {
2936:                        return v;
2937:                    }
2938:                } catch (Exception e) {
2939:                    // skip
2940:                }
2941:                if (defaultProperties != null) {
2942:                    return defaultProperties.getProperty(key);
2943:                } else {
2944:                    return null;
2945:                }
2946:            }
2947:
2948:            private Map beanAccessors = createWeakMap();
2949:
2950:            static class BeanInfoParam {
2951:                Class targetClass;
2952:
2953:                Class stopClass;
2954:
2955:                BeanInfoParam(Class targetClass, Class stopClass) {
2956:                    this .targetClass = targetClass;
2957:                    this .stopClass = stopClass;
2958:                }
2959:
2960:                public int hashCode() {
2961:                    return targetClass.hashCode() ^ stopClass.hashCode();
2962:                }
2963:
2964:                public boolean equals(Object that) {
2965:                    if (that instanceof  BeanInfoParam) {
2966:                        BeanInfoParam p = (BeanInfoParam) that;
2967:                        return p.targetClass == this .targetClass
2968:                                && p.stopClass == this .stopClass;
2969:                    }
2970:                    return false;
2971:                }
2972:            }
2973:
2974:            private Accessor getAccessor(Class cls, Class stopClass) {
2975:                Object key;
2976:                if (stopClass == null) {
2977:                    key = cls;
2978:                } else {
2979:                    key = new BeanInfoParam(cls, stopClass);
2980:                }
2981:                java.lang.ref.SoftReference ref = (java.lang.ref.SoftReference) beanAccessors
2982:                        .get(key);
2983:                if (ref == null) {
2984:                    Accessor a = createBeanAccessor(cls, stopClass);
2985:                    beanAccessors.put(key, new java.lang.ref.SoftReference(a));
2986:                    return a;
2987:                } else {
2988:                    Accessor a = (Accessor) ref.get();
2989:                    if (a == null) {
2990:                        a = createBeanAccessor(cls, stopClass);
2991:                        beanAccessors.put(key, new java.lang.ref.SoftReference(
2992:                                a));
2993:                    }
2994:                    return a;
2995:                }
2996:            }
2997:
2998:            private Accessor createBeanAccessor(Class cls, Class stopClass) {
2999:                return new Accessor(cls, stopClass);
3000:            }
3001:
3002:            /**
3003:             * Sets a Bean property of the specified bean.
3004:             * 
3005:             * @param context
3006:             *            the context
3007:             * @param target
3008:             *            the target bean
3009:             * @param name
3010:             *            the Bean property name
3011:             * @param value
3012:             *            the value of the Bean property
3013:             */
3014:            public static void setBeanProperty(Context context, Object target,
3015:                    String name, Object value) {
3016:                try {
3017:                    context.runtime.setBeanProperty(target, name, value, null);
3018:                } catch (IllegalAccessException e1) {
3019:                    throw new PnutsException(e1, context);
3020:                } catch (InvocationTargetException e2) {
3021:                    throw new PnutsException(e2.getTargetException(), context);
3022:                }
3023:            }
3024:
3025:            /**
3026:             * Gets a Bean property of the specified bean.
3027:             * 
3028:             * @param context
3029:             *            the context
3030:             * @param target
3031:             *            the target bean
3032:             * @param name
3033:             *            the Bean property name
3034:             */
3035:            public static Object getBeanProperty(Context context,
3036:                    Object target, String name) {
3037:                try {
3038:                    return context.runtime.getBeanProperty(target, name, null);
3039:                } catch (IllegalAccessException e1) {
3040:                    throw new PnutsException(e1, context);
3041:                } catch (InvocationTargetException e2) {
3042:                    throw new PnutsException(e2.getTargetException(), context);
3043:                }
3044:            }
3045:
3046:            /**
3047:             * Gets a Bean property of the specified bean.
3048:             * 
3049:             * @param target
3050:             *            the target bean
3051:             * @param name
3052:             *            the Bean property name
3053:             */
3054:            public Object getBeanProperty(Object target, String name)
3055:                    throws IllegalAccessException, InvocationTargetException {
3056:                return getBeanProperty(target, name, null);
3057:            }
3058:
3059:            /**
3060:             * Gets a Bean property of the specified bean.
3061:             * 
3062:             * @param target
3063:             *            the target bean
3064:             * @param name
3065:             *            the Bean property name
3066:             * @param stopClass
3067:             *            the Introspector's "stopClass"
3068:             */
3069:            protected Object getBeanProperty(Object target, String name,
3070:                    Class stopClass) throws IllegalAccessException,
3071:                    InvocationTargetException {
3072:                Accessor a = getAccessor(target.getClass(), stopClass);
3073:                Method readMethod = (Method) a.findReadMethod(name);
3074:                if (readMethod != null) {
3075:                    try {
3076:                        return readMethod.invoke(target, noarg);
3077:                    } catch (IllegalAccessException e1) {
3078:                        Class cls = readMethod.getDeclaringClass();
3079:                        if (!Modifier.isPublic(cls.getModifiers())) {
3080:                            Method _m = findCallableMethod(cls, readMethod
3081:                                    .getName(), readMethod.getParameterTypes());
3082:                            if (_m != null) {
3083:                                a.addReadMethod(name, _m);
3084:                                if (DEBUG) {
3085:                                    System.out.println("addReadMethod " + _m);
3086:                                }
3087:                                try {
3088:                                    return _m.invoke(target, noarg);
3089:                                } catch (IllegalAccessException iae) {
3090:                                }
3091:                            }
3092:                        }
3093:                        return Configuration.normalConfiguration.reInvoke(e1,
3094:                                readMethod, target, noarg);
3095:                    }
3096:                } else {
3097:                    if (target instanceof  Class) {
3098:                        Class cls = (Class) target;
3099:                        Field field = getField(cls, name);
3100:                        if (field != null
3101:                                && Modifier.isStatic(field.getModifiers())) {
3102:                            return field.get(null);
3103:                        }
3104:                    }
3105:                    if (a.findWriteMethod(name) == null) {
3106:                        Class cls = target.getClass();
3107:                        Field field = getField(cls, name);
3108:                        if (field != null
3109:                                && !Modifier.isStatic(field.getModifiers())) {
3110:                            return field.get(target);
3111:                        }
3112:                    }
3113:                    throw new IllegalArgumentException(
3114:                            "not readable property: target=" + target
3115:                                    + ", fieldName=" + name);
3116:                }
3117:            }
3118:
3119:            protected Cache fieldCache = createCache();
3120:
3121:            protected Field getField(final Class cls, final String name) {
3122:                Cache fc = (Cache) fieldCache.get(cls);
3123:                if (fc == null) {
3124:                    fc = createCache();
3125:                    fieldCache.put(cls, fc);
3126:                }
3127:                Field field = (Field) fc.get(name);
3128:                if (field == null) {
3129:                    try {
3130:                        field = (Field) AccessController
3131:                                .doPrivileged(new PrivilegedExceptionAction() {
3132:                                    public Object run() throws Exception {
3133:                                        return cls.getField(name);
3134:                                    }
3135:                                });
3136:                        fc.put(name, field);
3137:                    } catch (PrivilegedActionException e) {
3138:                        return null;
3139:                    }
3140:                }
3141:                return field;
3142:            }
3143:
3144:            /**
3145:             * Sets a Bean property of the specified bean.
3146:             * 
3147:             * @param target
3148:             *            the target bean
3149:             * @param name
3150:             *            the Bean property name
3151:             * @param value
3152:             *            the new property value
3153:             */
3154:            public void setBeanProperty(Object target, String name, Object value)
3155:                    throws IllegalAccessException, InvocationTargetException {
3156:                setBeanProperty(target, name, value, null);
3157:            }
3158:
3159:            /**
3160:             * Sets a Bean property of the specified bean.
3161:             * 
3162:             * @param target
3163:             *            the target bean
3164:             * @param name
3165:             *            the Bean property name
3166:             * @param value
3167:             *            the new property value
3168:             * @param stopClass
3169:             *            the Introspector's "stopClass"
3170:             */
3171:            protected void setBeanProperty(Object target, String name,
3172:                    Object value, Class stopClass)
3173:                    throws IllegalAccessException, InvocationTargetException {
3174:                Accessor a = getAccessor(target.getClass(), stopClass);
3175:                Method writeMethod = (Method) a.findWriteMethod(name);
3176:                if (writeMethod != null) {
3177:                    Class type = writeMethod.getParameterTypes()[0];
3178:                    Object[] arg = null;
3179:                    try {
3180:                        if (type.isArray() && !type.isInstance(value)) {
3181:                            value = transform(type, value, null);
3182:                        } else if (type.isPrimitive()) {
3183:                            value = primitive(type, value, false, 10);
3184:                        } else if (List.class.isAssignableFrom(type)) {
3185:                            value = transform(type, value, null);
3186:                        }
3187:                        arg = new Object[] { value };
3188:                        writeMethod.invoke(target, arg);
3189:                        return;
3190:                    } catch (IllegalArgumentException iae) {
3191:                        String msg = Runtime.getMessage("pnuts.lang.pnuts",
3192:                                "type.mismatch",
3193:                                new Object[] { type, target, name, value,
3194:                                        value.getClass().getName() });
3195:                        throw new IllegalArgumentException(msg);
3196:                    } catch (ClassCastException cce) {
3197:                        String msg = Runtime.getMessage("pnuts.lang.pnuts",
3198:                                "type.mismatch",
3199:                                new Object[] { type, target, name, value,
3200:                                        value.getClass().getName() });
3201:                        throw new IllegalArgumentException(msg);
3202:                    } catch (IllegalAccessException e1) {
3203:                        Class cls = writeMethod.getDeclaringClass();
3204:                        if (!Modifier.isPublic(cls.getModifiers())) {
3205:                            Method _m = findCallableMethod(cls, writeMethod
3206:                                    .getName(), writeMethod.getParameterTypes());
3207:                            if (_m != null) {
3208:                                a.addWriteMethod(name, _m);
3209:                                if (DEBUG) {
3210:                                    System.out.println("addWriteMethod " + _m);
3211:                                }
3212:                                try {
3213:                                    _m.invoke(target, arg);
3214:                                    return;
3215:                                } catch (IllegalAccessException iae) {
3216:                                }
3217:                            }
3218:                        }
3219:                        Configuration.normalConfiguration.reInvoke(e1,
3220:                                writeMethod, target, arg);
3221:                        return;
3222:                    }
3223:                } else {
3224:                    if (target instanceof  Class) {
3225:                        Class cls = (Class) target;
3226:                        Field field = getField(cls, name);
3227:                        if (field != null
3228:                                && Modifier.isStatic(field.getModifiers())) {
3229:                            field.set(null, value);
3230:                            return;
3231:                        }
3232:                    }
3233:                    if (a.findReadMethod(name) == null) {
3234:                        Class cls = target.getClass();
3235:                        Field field = getField(cls, name);
3236:                        if (field != null
3237:                                && !Modifier.isStatic(field.getModifiers())) {
3238:                            field.set(target, value);
3239:                            return;
3240:                        }
3241:                    }
3242:                    throw new IllegalArgumentException(
3243:                            "not writable property: target=" + target
3244:                                    + ", fieldName=" + name);
3245:                }
3246:            }
3247:
3248:            /**
3249:             * Gets the type of a bean property
3250:             * 
3251:             * @param cls
3252:             *            the class of the bean
3253:             * @param name
3254:             *            the property name of the bean property
3255:             * @return the type of the property
3256:             */
3257:            public Class getBeanPropertyType(Class cls, String name) {
3258:                return getAccessor(cls, null).getType(name);
3259:            }
3260:
3261:            public static class Break extends RuntimeException {
3262:                Object value;
3263:
3264:                public Break(Object value) {
3265:                    this .value = value;
3266:                }
3267:
3268:                public Object getValue() {
3269:                    return value;
3270:                }
3271:            }
3272:
3273:            public static class Continue extends RuntimeException {
3274:            }
3275:
3276:            public static boolean isGenerator(SimpleNode node) {
3277:                int n = node.jjtGetNumChildren();
3278:                for (int i = 0; i < n; i++) {
3279:                    SimpleNode c = node.jjtGetChild(i);
3280:                    if (c.id == PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT) {
3281:                        continue;
3282:                    }
3283:                    if (c.id == PnutsParserTreeConstants.JJTYIELD) {
3284:                        return true;
3285:                    } else {
3286:                        if (isGenerator(c)) {
3287:                            return true;
3288:                        }
3289:                    }
3290:                }
3291:                return false;
3292:            }
3293:
3294:            static class RangeGenerator extends Generator {
3295:                Generator gen;
3296:
3297:                int pos = 0;
3298:
3299:                int start, end;
3300:
3301:                RangeGenerator(Generator gen, int start) {
3302:                    this (gen, start, -1);
3303:                }
3304:
3305:                RangeGenerator(Generator gen, int start, int end) {
3306:                    this .gen = gen;
3307:                    this .start = start;
3308:                    this .end = end;
3309:                }
3310:
3311:                public Object apply(final PnutsFunction closure, Context context) {
3312:                    return gen.apply(new PnutsFunction() {
3313:                        protected Object exec(Object[] args, Context c) {
3314:                            if (pos < start) {
3315:                                pos++;
3316:                                return null;
3317:                            } else if (start < 0 || end >= 0 && pos > end) {
3318:                                throw new Generator.Break(null);
3319:                            } else {
3320:                                pos++;
3321:                                return closure.call(args, c);
3322:                            }
3323:                        }
3324:                    }, context);
3325:                }
3326:            }
3327:
3328:            public static Object applyGenerator(Generator g,
3329:                    PnutsFunction closure, Context context) {
3330:                try {
3331:                    return g.apply(closure, context);
3332:                } catch (Generator.Break brk) {
3333:                    return brk.getValue();
3334:                }
3335:            }
3336:
3337:            public static void addImport(Context context, String name) {
3338:                if (name.endsWith(".*")) {
3339:                    name = name.substring(0, name.length() - 2);
3340:                    context.addPackageToImport(name);
3341:                } else if ("*".equals(name)) {
3342:                    context.addPackageToImport("");
3343:                } else {
3344:                    context.addClassToImport(name);
3345:                }
3346:            }
3347:
3348:            public static void addStaticMembers(Context context, String name,
3349:                    boolean wildcard) {
3350:                context.addStaticMembers(name, wildcard);
3351:            }
3352:
3353:            protected static PnutsFunction defineUnboundFunction(Function f,
3354:                    String symbol, Package pkg) {
3355:                Value v = pkg.lookup(symbol);
3356:                if (v != null) {
3357:                    Object o = v.get();
3358:                    if (o instanceof  PnutsFunction) {
3359:                        return f.register((PnutsFunction) o, true);
3360:                    }
3361:                }
3362:                return f.register(null);
3363:            }
3364:
3365:            static Object lookupTopLevelValue(String symbol, Context context) {
3366:                Value v;
3367:                ModuleList moduleList = context.moduleList;
3368:                if (moduleList != null) {
3369:                    v = moduleList.resolve(symbol, context);
3370:                    if (v != null) {
3371:                        return v.get();
3372:                    }
3373:                }
3374:                Package parent = context.currentPackage.getParent();
3375:                while (parent != null) {
3376:                    v = parent.lookup(symbol);
3377:                    if (v != null) {
3378:                        return v.get();
3379:                    }
3380:                    parent = parent.getParent();
3381:                }
3382:                return null;
3383:            }
3384:
3385:            protected static PnutsFunction defineTopLevelFunction(Function f,
3386:                    String symbol, Package pkg, Context context) {
3387:                Value value = pkg.lookup(symbol);
3388:                Object o = null;
3389:                if (value != null) {
3390:                    o = value.get();
3391:                }
3392:                PnutsFunction pf;
3393:                if (o instanceof  PnutsFunction) {
3394:                    pf = f.register((PnutsFunction) o);
3395:                } else {
3396:                    o = lookupTopLevelValue(symbol, context);
3397:                    if (o instanceof  PnutsFunction) {
3398:                        pf = f.register((PnutsFunction) o, true);
3399:                    } else {
3400:                        pf = f.register(null);
3401:                    }
3402:                }
3403:                pkg.set(symbol, pf, context);
3404:                return pf;
3405:            }
3406:
3407:            public static String unparse(SimpleNode node, Context context) {
3408:                StringBuffer sbuf = new StringBuffer();
3409:                Visitor unparseVisitor = new UnparseVisitor(sbuf);
3410:                node.accept(unparseVisitor, context);
3411:                return sbuf.toString();
3412:            }
3413:
3414:            static void recoverParseError(PnutsParser parser, int tokenType) {
3415:                try {
3416:                    Token t;
3417:                    do {
3418:                        t = parser.getNextToken();
3419:                    } while (t.kind != tokenType
3420:                            && t.kind != PnutsParserConstants.EOF);
3421:                } catch (Exception e) {
3422:                    /* skip */
3423:                }
3424:            }
3425:
3426:            static class ThreadLocalContext extends ThreadLocal {
3427:            }
3428:
3429:            static ThreadLocal threadContext = new ThreadLocalContext();
3430:
3431:            /**
3432:             * Gets the context bound to the current thread
3433:             *
3434:             * @param context the context
3435:             */
3436:            public static void setThreadContext(Context context) {
3437:                threadContext.set(context);
3438:            }
3439:
3440:            /**
3441:             * Sets the context bound to the current thread
3442:             *
3443:             * @return the context
3444:             */
3445:            public static Context getThreadContext() {
3446:                return (Context) threadContext.get();
3447:            }
3448:
3449:            static ImportEnv getDefaultImports(Context context) {
3450:                ImportEnv importEnv = new ImportEnv();
3451:                String[] array = context.config.getDefaultImports();
3452:                for (int i = 0; i < array.length; i++) {
3453:                    String name = array[i];
3454:                    if (name.startsWith("static ")) {
3455:                        if (name.endsWith(".*")) {
3456:                            name = name.substring(0, name.length() - 2);
3457:                            importEnv.addStaticMembers(name, true, context);
3458:                        } else {
3459:                            importEnv.addStaticMembers(name, false, context);
3460:                        }
3461:                    } else {
3462:                        if (name.endsWith(".*")) {
3463:                            name = name.substring(0, name.length() - 2);
3464:                            importEnv.addPackage(name);
3465:                        } else if ("*".equals(name)) {
3466:                            importEnv.addPackage("");
3467:                        } else {
3468:                            importEnv.addClass(name);
3469:                        }
3470:                    }
3471:                }
3472:                return importEnv;
3473:            }
3474:
3475:            public static interface FunctionSerializer {
3476:                void serialize(PnutsFunction pnutsFunction, ObjectOutputStream s)
3477:                        throws IOException;
3478:
3479:                void deserialize(PnutsFunction pnutsFunction,
3480:                        ObjectInputStream s) throws IOException,
3481:                        ClassNotFoundException;
3482:            }
3483:
3484:            static FunctionSerializer functionSerializer;
3485:            static {
3486:                try {
3487:                    Class cls = Class
3488:                            .forName("pnuts.lang.DefaultFunctionSerializer");
3489:                    functionSerializer = (FunctionSerializer) cls.newInstance();
3490:                } catch (Exception e) {
3491:                    try {
3492:                        Class cls = Class
3493:                                .forName("pnuts.lang.SimpleFunctionSerializer");
3494:                        functionSerializer = (FunctionSerializer) cls
3495:                                .newInstance();
3496:                    } catch (Exception e2) {
3497:                        // skip
3498:                    }
3499:                }
3500:            }
3501:
3502:            static void serializePnutsFunction(PnutsFunction pnutsFunction,
3503:                    ObjectOutputStream s) throws IOException {
3504:                functionSerializer.serialize(pnutsFunction, s);
3505:            }
3506:
3507:            static void deserializePnutsFunction(PnutsFunction pnutsFunction,
3508:                    ObjectInputStream s) throws IOException,
3509:                    ClassNotFoundException {
3510:                functionSerializer.deserialize(pnutsFunction, s);
3511:            }
3512:
3513:            public static String saveNode(SimpleNode node) {
3514:                return NodeUtil.saveNode(node);
3515:            }
3516:
3517:            public static SimpleNode loadNode(String str) {
3518:                return NodeUtil.loadNode(str);
3519:            }
3520:
3521:            private static boolean useCacheCleanerThread;
3522:            static {
3523:                String prop = getProperty("pnuts.lang.useCacheCleanerThread");
3524:                useCacheCleanerThread = (prop == null || !prop.toLowerCase()
3525:                        .equals("false"));
3526:            }
3527:
3528:            public static Map createWeakMap() {
3529:                if (useCacheCleanerThread) {
3530:                    return new org.pnuts.util.RefMap();
3531:                } else {
3532:                    return new WeakHashMap();
3533:                }
3534:            }
3535:
3536:            public static Cache createCache() {
3537:                if (useCacheCleanerThread) {
3538:                    return new MemoryCache(createWeakMap());
3539:                } else {
3540:                    return new MemoryCache();
3541:                }
3542:            }
3543:
3544:            /**
3545:            public static String unparseNode(SimpleNode node){
3546:            	StringBuffer sbuf = new StringBuffer();
3547:            	node.accept(new org.pnuts.lang.UnparseVisitor(sbuf), null);
3548:            	return sbuf.toString();
3549:            }
3550:             **/
3551:
3552:            /* experimental BIND feature */
3553:
3554:            protected static void setupPropertyChangeListeners(Map table,
3555:                    Context context) {
3556:                for (Iterator it = table.entrySet().iterator(); it.hasNext();) {
3557:                    Map.Entry memberTargetEntry = (Map.Entry) it.next();
3558:                    Object memberTarget = memberTargetEntry.getKey();
3559:                    Map memberNameTable = (Map) memberTargetEntry.getValue(); // memberName -> list of [obj, property, rhs]
3560:                    setupPropertyChangeListeners(memberTarget, memberNameTable,
3561:                            context);
3562:
3563:                }
3564:            }
3565:
3566:            private static void setupPropertyChangeListeners(
3567:                    Object memberTarget, Map memberNameTable, Context context) {
3568:                PropertyChangeListener listener = new PropertyWatcher(
3569:                        memberNameTable, context);
3570:                addPropertyChangeListener(memberTarget, listener, context);
3571:            }
3572:
3573:            private static void addPropertyChangeListener(Object obj,
3574:                    PropertyChangeListener listener, Context context) {
3575:                /*
3576:                Class cls = obj.getClass();
3577:                try {
3578:                    Method addMethod = cls.getMethod("addPropertyChangeListener", new Class[]{PropertyChangeListener.class});
3579:                    addMethod.invoke(obj, new Object[]{listener});
3580:                } catch (Exception e){
3581:                    throw new PnutsException(e, context);
3582:                }
3583:                 */
3584:                callMethod(context, obj.getClass(),
3585:                        "addPropertyChangeListener", new Object[] { listener },
3586:                        new Class[] { PropertyChangeListener.class }, obj);
3587:            }
3588:
3589:            /*
3590:             * Whenever memberTarget.memberName changes, rhs.accept(this, context) is evaluated and assigned to obj.property
3591:             *
3592:             * table = Map of (memberTarget -> Map of (memberName -> [obj, property, rhs])) is maintained somewhere,
3593:             * and this method does the followings.
3594:             * 1. if (table.memberTarget) == null, then table.memberTareget = map()
3595:             * 2. if (table.memberTareget.memberName == null), then table.memberTareget.memberName = list()
3596:             * 3. table.memberTareget.memberName.add([obj, property, rhs])
3597:             *
3598:             */
3599:            protected static void watchProperty(Map table, Object obj,
3600:                    String property, Object memberTarget, String memberName,
3601:                    Callable rhs) {
3602:                if (canAcceptPropertyChangeListener(memberTarget)) {
3603:                    Map memberNameTable = (Map) table.get(memberTarget);
3604:                    if (memberNameTable == null) {
3605:                        memberNameTable = new HashMap();
3606:                        table.put(memberTarget, memberNameTable);
3607:                    }
3608:                    List tupleList = (List) memberNameTable.get(memberName);
3609:                    if (tupleList == null) {
3610:                        tupleList = new ArrayList();
3611:                        memberNameTable.put(memberName, tupleList);
3612:                    }
3613:                    tupleList.add(new Object[] { obj, property, rhs });
3614:                }
3615:            }
3616:
3617:            private static boolean canAcceptPropertyChangeListener(Object obj) {
3618:                try {
3619:                    Method addMethod = obj.getClass().getMethod(
3620:                            "addPropertyChangeListener",
3621:                            new Class[] { PropertyChangeListener.class });
3622:                    return true;
3623:                } catch (Exception e) {
3624:                }
3625:                return false;
3626:            }
3627:
3628:            protected static SimpleNode toFunctionNode(SimpleNode body) {
3629:                SimpleNode bodyClone = loadNode(saveNode(body));
3630:                SimpleNode f = new SimpleNode(
3631:                        PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT);
3632:                SimpleNode param = new SimpleNode(
3633:                        PnutsParserTreeConstants.JJTLISTELEMENTS);
3634:                f.jjtAddChild(bodyClone, 1);
3635:                f.jjtAddChild(param, 0);
3636:                bodyClone.jjtSetParent(f);
3637:                param.jjtSetParent(f);
3638:                return f;
3639:            }
3640:
3641:            static class PropertyWatcher implements  PropertyChangeListener {
3642:                private Map memberNameTable;
3643:                private Context context;
3644:
3645:                PropertyWatcher(Map memberNameTable, Context context) {
3646:                    this .memberNameTable = memberNameTable;
3647:                    this .context = context;
3648:                }
3649:
3650:                public void propertyChange(PropertyChangeEvent e) {
3651:                    String name = e.getPropertyName();
3652:                    List tuples = (List) memberNameTable.get(name);
3653:                    if (tuples != null) {
3654:                        int size = tuples.size();
3655:                        for (int i = 0; i < size; i++) {
3656:                            Object[] tuple = (Object[]) tuples.get(i);
3657:                            Object target = tuple[0];
3658:                            String targetProperty = (String) tuple[1];
3659:                            Callable rhs = (Callable) tuple[2];
3660:                            Object value = rhs != null ? rhs.call(NO_PARAM,
3661:                                    context) : e.getNewValue();
3662:                            context.config.putField(context, target,
3663:                                    targetProperty, value);
3664:                        }
3665:                    }
3666:                }
3667:            }
3668:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.