001: /*
002: * PnutsImpl.java
003: *
004: * Copyright (c) 1997-2007 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.lang;
010:
011: import java.io.File;
012: import java.io.FileNotFoundException;
013: import java.io.IOException;
014: import java.io.InputStream;
015: import java.net.URL;
016: import java.util.Iterator;
017: import java.util.Map;
018: import java.util.Properties;
019:
020: /**
021: * This class defines an abstract interface of script interpreter's
022: * implementation, It also gives the default implementation, which is a pure
023: * interpreter.
024: *
025: * @see pnuts.lang.Context#setImplementation(Implementation)
026: * @see pnuts.lang.Context#getImplementation()
027: */
028: public class PnutsImpl extends Runtime implements Implementation {
029:
030: static PnutsImpl defaultPnutsImpl = _getInstance();
031: protected Properties properties = new Properties();
032:
033: static PnutsImpl _getInstance() {
034: return _getInstance(Runtime
035: .getProperty("pnuts.lang.defaultPnutsImpl"));
036: }
037:
038: static PnutsImpl _getInstance(String className) {
039: return _getInstance(className, Pnuts.defaultSettings);
040: }
041:
042: static PnutsImpl _getInstance(String className,
043: Properties properties) {
044: PnutsImpl impl = null;
045: if (className != null) {
046: try {
047: Class cls = Class.forName(className);
048: impl = (PnutsImpl) cls.newInstance();
049: } catch (Exception e) {
050: }
051: }
052: if (impl == null) {
053: impl = new PnutsImpl();
054: }
055: if (properties != null) {
056: impl.setProperties(properties);
057: }
058: return impl;
059: }
060:
061: /**
062: * Returns the default PnutsImpl object
063: *
064: * @return the default PnutsImpl object
065: */
066: public static PnutsImpl getDefault() {
067: return defaultPnutsImpl;
068: }
069:
070: static PnutsImpl getDefault(Properties properties) {
071: try {
072: return _getInstance(properties
073: .getProperty("pnuts.lang.defaultPnutsImpl"),
074: properties);
075: } catch (Exception e) {
076: e.printStackTrace();
077: }
078: return new PnutsImpl();
079: }
080:
081: public void setProperties(Properties properties) {
082: for (Iterator it = properties.entrySet().iterator(); it
083: .hasNext();) {
084: Map.Entry entry = (Map.Entry) it.next();
085: setProperty((String) entry.getKey(), (String) entry
086: .getValue());
087: }
088: }
089:
090: public void setProperty(String key, String value) {
091: this .properties.setProperty(key, value);
092: }
093:
094: public String queryProperty(String key) {
095: return this .properties.getProperty(key);
096: }
097:
098: /**
099: * Evaluate an expreesion
100: *
101: * @param expr
102: * the expression to be evaluated
103: * @param context
104: * the context in which the expression is evaluated
105: * @return the result of the evaluation
106: */
107: public Object eval(String expr, Context context) {
108: try {
109: return Pnuts.parse(expr).accept(
110: PnutsInterpreter.getInstance(), context);
111: } catch (ParseException e) {
112: context.beginLine = e.getErrorLine();
113: checkException(context, e);
114: return null;
115: } finally {
116: context.eval = false;
117: }
118: }
119:
120: /**
121: * Load a script file from local file system
122: *
123: * @param filename
124: * the file name of the script
125: * @param context
126: * the context in which the expression is evaluated
127: * @return the result of the evaluation
128: */
129: public Object loadFile(String filename, Context context)
130: throws FileNotFoundException {
131: URL scriptURL = null;
132: try {
133: File f = new File(filename);
134: if (!f.exists()) {
135: throw new FileNotFoundException(filename);
136: }
137: scriptURL = Runtime.fileToURL(f);
138: } catch (IOException e1) {
139: throw new FileNotFoundException(filename);
140: }
141: return load(scriptURL, context);
142: }
143:
144: /**
145: * Load a script file using classloader
146: *
147: * @param file
148: * the name of the script
149: * @param context
150: * the context in which the script is executed
151: * @return the result of the evaluation
152: */
153: public Object load(String file, Context context)
154: throws FileNotFoundException {
155: URL url = Runtime.getScriptURL(file, context);
156: if (url == null) {
157: throw new FileNotFoundException(file);
158: }
159: provide(file, context);
160: boolean completed = false;
161: try {
162: Object result = load(url, context);
163: completed = true;
164: return result;
165: } finally {
166: if (!completed) {
167: revoke(file, context);
168: }
169: }
170: }
171:
172: /**
173: * Load a script file from a URL
174: *
175: * @param scriptURL
176: * the URL of the script
177: * @param context
178: * the context in which the script is executed
179: * @return the result of the evaluation
180: */
181: public Object load(URL scriptURL, Context context) {
182: InputStream in = null;
183: Object value = null;
184: int depth = Pnuts.enter(context);
185: Throwable error = null;
186: try {
187: pushFile(scriptURL, context);
188: in = scriptURL.openStream();
189: value = accept(Pnuts.parse(Runtime.getScriptReader(in,
190: context)).startNodes, context);
191: context.onExit(value);
192: return value;
193: } catch (ParseException e) {
194: context.beginLine = e.getErrorLine();
195: error = e;
196: checkException(context, e);
197: error = null;
198: return null;
199: } catch (Jump jump) {
200: context.onExit(value);
201: return jump.getValue();
202: } catch (Escape esc) {
203: context.onExit(value);
204: if (context.depth > 1) {
205: throw esc;
206: }
207: return esc.getValue();
208: } catch (Throwable e) {
209: error = e;
210: checkException(context, e);
211: error = null;
212: return null;
213: } finally {
214: if (error != null) {
215: context.onError(error);
216: }
217: popFile(context);
218: context.depth = depth;
219: if (in != null) {
220: try {
221: in.close();
222: } catch (IOException io) {
223: }
224: }
225: }
226: }
227:
228: protected Object acceptNode(SimpleNode node, Context context) {
229: return node.accept(PnutsInterpreter.getInstance(), context);
230: }
231:
232: public Object accept(SimpleNode node, Context context) {
233: Context old = getThreadContext();
234: if (context != old) {
235: setThreadContext(context);
236: }
237: try {
238: return acceptNode(node, context);
239: } finally {
240: if (old != context) {
241: setThreadContext(old);
242: }
243: }
244: }
245:
246: /**
247: * Tell the context that it's started processing the script file.
248: */
249: protected void pushFile(Object file, Context context) {
250: context.pushFile(file);
251: }
252:
253: /**
254: * Tell the context that the current script file has been completed.
255: */
256: protected void popFile(Context context) {
257: context.popFile();
258: }
259:
260: protected void provide(String file, Context context) {
261: if (file.endsWith(".pnut")) {
262: file = file.substring(0, file.length() - 5);
263: }
264: context.provide(file);
265: }
266:
267: protected void revoke(String file, Context context) {
268: if (file.endsWith(".pnut")) {
269: file = file.substring(0, file.length() - 5);
270: }
271: context.revoke(file);
272: }
273: }
|