001: /*
002: * @(#)ScriptPackage.java 1.2 04/12/06
003: *
004: * Copyright (c) 1997-2004 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.lib;
010:
011: import pnuts.lang.Pnuts;
012: import pnuts.lang.PnutsImpl;
013: import pnuts.lang.Implementation;
014: import pnuts.lang.Runtime;
015: import pnuts.lang.Context;
016: import pnuts.lang.Package;
017: import pnuts.lang.AbstractData;
018: import pnuts.lang.PnutsFunction;
019: import pnuts.lang.PnutsException;
020: import java.io.OutputStream;
021: import java.io.StringWriter;
022: import java.io.ObjectOutputStream;
023: import java.io.IOException;
024: import java.util.Enumeration;
025:
026: /**
027: * Package that is used in user's scripts as an hashtable.
028: * Unlike pnuts.lang.Package, this class implements AbstractData, so that
029: * expression like <code>scriptPackage.fname(args...)</code> is interpreted as
030: * a call of function 'fname' of the script package.
031: *
032: * When <code>scriptPackage.print</code> is a zero-arg function,
033: * ScriptPackage.toString() method calls the function to obtain the string
034: * representation of the object.
035: */
036: public class ScriptPackage extends Package implements AbstractData {
037:
038: private static Implementation pureImpl = new PnutsImpl();
039:
040: public ScriptPackage() {
041: }
042:
043: public ScriptPackage(String name) {
044: this (name, null);
045: }
046:
047: public ScriptPackage(String name, Package parent) {
048: super (name, parent, null);
049: }
050:
051: public Object invoke(String name, Object args[], Context context) {
052: Object o = get(name, context);
053: if (o instanceof PnutsFunction) {
054: return ((PnutsFunction) o).call(args, context);
055: } else if (o instanceof Class) {
056: return context.getConfiguration().callConstructor(context,
057: (Class) o, args, null);
058: } else {
059: throw new PnutsException("funcOrType.expected",
060: new Object[] { Pnuts.format(o) }, context);
061: }
062: }
063:
064: /**
065: * Defines a special function to create <a href="../../../doc/script_package.html">script packages</a>.
066: */
067: public static class Function extends PnutsFunction implements
068: AbstractData {
069:
070: private Package prototype;
071:
072: public Function() {
073: this ("$");
074: }
075:
076: public Function(String name) {
077: this (name, new ScriptPackage(null, null));
078: }
079:
080: public Function(String name, Package prototype) {
081: super (name);
082: this .prototype = prototype;
083: }
084:
085: /**
086: * @return null
087: */
088: public Object get(String name, Context context) {
089: return null;
090: }
091:
092: /**
093: * Do nothing.
094: */
095: public void set(String name, Object value, Context context) {
096: }
097:
098: /**
099: * Provides these methods:
100: *<pre>
101: * $.set(pkg, "name", value)
102: * $.get(pkg, "name")
103: * $.defined(pkg, "name")
104: * $.clear(pkg, "name")
105: * $.keys(pkg)
106: * $.save(pkg, stream)
107: * $.clone(pkg)
108: *</pre>
109: */
110: public Object invoke(String name, Object[] args, Context context) {
111: if ("call".equals(name)) {
112: return call(args, context);
113: } else if ("set".equals(name)) {
114: if (args.length == 3) {
115: Package pkg = (Package) args[0];
116: String sym = (String) args[1];
117: Object value = args[2];
118: pkg.set(sym.intern(), value, context);
119: return null;
120: }
121: } else if ("get".equals(name)) {
122: if (args.length == 2) {
123: Package pkg = (Package) args[0];
124: String sym = (String) args[1];
125: return pkg.get(sym.intern(), context);
126: }
127: } else if ("clear".equals(name)) {
128: if (args.length == 2) {
129: Package pkg = (Package) args[0];
130: String sym = (String) args[1];
131: pkg.clear(sym.intern(), context);
132: return null;
133: }
134: } else if ("defined".equals(name)) {
135: if (args.length == 2) {
136: Package pkg = (Package) args[0];
137: String sym = (String) args[1];
138: boolean b = pkg.defined(sym.intern(), context);
139: return b ? Boolean.TRUE : Boolean.FALSE;
140: }
141: } else if ("keys".equals(name)) {
142: if (args.length == 1) {
143: Package pkg = (Package) args[0];
144: return pkg.keys();
145: }
146: } else if ("clone".equals(name)) {
147: if (args.length == 1) {
148: Package pkg = (Package) args[0];
149: return pkg.clone();
150: }
151: } else if ("save".equals(name)) {
152: if (args.length == 2) {
153: Package pkg = (Package) args[0];
154: try {
155: ObjectOutputStream o = new ObjectOutputStream(
156: (OutputStream) args[1]);
157: o.writeObject(pkg);
158: return null;
159: } catch (IOException e) {
160: throw new PnutsException(e, context);
161: }
162: }
163: }
164: throw new PnutsException("method.notFound", new Object[] {
165: name, Function.this .toString(),
166: "" + Pnuts.format(args) }, context);
167: }
168:
169: public boolean defined(int nargs) {
170: return nargs >= -1;
171: }
172:
173: /**
174: * Creates a <a href="../../../doc/script_package.html">script package</a>.
175: */
176: protected Object exec(Object[] args, Context context) {
177: if (args.length == 0) {
178: return prototype.clone();
179: } else if (args.length == 1 && args[0] instanceof String) {
180: Context c = new Context(context);
181: c.setImplementation(pureImpl);
182: Package p = (Package) prototype.clone();
183: c.setCurrentPackage(p);
184: Pnuts.eval((String) args[0], c);
185: return p;
186: } else if (args.length == 1 && args[0] instanceof Object[]) {
187: Object[] list = (Object[]) args[0];
188: Package sp = (Package) prototype.clone();
189: for (int i = 0; i < list.length; i++) {
190: Object[] pair = (Object[]) list[i];
191: String name = (String) pair[0];
192: sp.set(name.intern(), pair[1], context);
193: }
194: return sp;
195: } else {
196: Package sp = (Package) prototype.clone();
197: for (int i = 0; i < args.length; i++) {
198: Object arg = args[i];
199: if (arg instanceof PnutsFunction) {
200: String name = ((PnutsFunction) arg).getName();
201: if (name != null) {
202: int idx = name.lastIndexOf('.');
203: if (idx >= 0) {
204: name = name.substring(idx + 1);
205: }
206: sp.set(name.intern(), arg, context);
207: }
208: }
209: }
210: return sp;
211: }
212: }
213: }
214:
215: private final static String PRINT_FUNCTION = "print".intern();
216:
217: public PnutsFunction getPrintFunction() {
218: Object o = get(PRINT_FUNCTION);
219: if (o instanceof PnutsFunction) {
220: PnutsFunction f = (PnutsFunction) o;
221: if (f.defined(0)) {
222: return f;
223: }
224: }
225: return null;
226: }
227:
228: public String toString() {
229: PnutsFunction printFunction = getPrintFunction();
230: if (printFunction != null) {
231: Context context = new Context();
232: StringWriter sw = new StringWriter();
233: context.setWriter(sw);
234: printFunction.call(new Object[] {}, context);
235: return sw.toString();
236: } else {
237: return "<script package>";
238: }
239: }
240: }
|