001: package murlen.util.fscript;
002:
003: import java.io.IOException;
004: import java.io.Reader;
005: import java.util.ArrayList;
006:
007: /**
008: * <p>Femto Script - This is the main FScript package class</p>
009: * <p>
010: * <I>Copyright (C) 2000-2003 murlen.</I></p>
011: * <p>
012: * This library is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU Library General Public
014: * License as published by the Free Software Foundation; either
015: * version 2 of the License, or (at your option) any later version.</p>
016: * <p>
017: * This library is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
020: * Library General Public License for more details.</p>
021: *
022: * <p>You should have received a copy of the GNU Library General Public
023: * License along with this library; if not, write to the Free
024: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA </p>
025: * @author murlen
026: * @author Joachim Van der Auwera
027: * @version 1.12
028: *
029: * modifications by Joachim Van der Auwera
030: * 02.08.2002 added support for FSParserExtension
031: * 15.03.2003 getContext()
032: */
033:
034: public class FScript implements FSExtension {
035:
036: private Parser parser;
037: private LineLoader code;
038: private ArrayList extensions;
039:
040: /** Constructor */
041: public FScript() {
042:
043: parser = new Parser(this );
044: code = new LineLoader();
045: parser.setCode(code);
046: extensions = new ArrayList();
047:
048: }
049:
050: /**
051: * Loads FScript parser with text from an InputStreamReader
052: * @param is the input stream
053: */
054: public void load(Reader is) throws IOException {
055: code.load(is);
056: }
057:
058: /**
059: * Load an individual line into the parser, intended for
060: * document processing applications
061: * @param line the line to load
062: */
063: public void loadLine(String line) {
064: code.addLine(line);
065: }
066:
067: /**
068: *Registers language extensions
069: *@param extension the extension to register
070: **/
071: public void registerExtension(FSExtension extension) {
072: if (extension instanceof FSParserExtension)
073: ((FSParserExtension) extension).setParser(parser);
074: extensions.add(extension);
075: }
076:
077: /**
078: *Removes a previously registered extenison
079: *@param extension the extension to remove
080: **/
081: public void unRegisterExtension(FSExtension extension) {
082: extensions.remove(extension);
083: }
084:
085: /**
086: * Run the parser over currently loaded code
087: *@return any return value of the script's execution (will be one of
088: *FScript's supported type objects, Integer,String,Double)
089: */
090: public Object run() throws IOException, FSException {
091: //reset the internal variable state
092: parser.reset();
093: return parser.parse(0, code.lineCount() - 1);
094: }
095:
096: public Object evaluateExpression(String expr) throws IOException,
097: FSException {
098: if (!expr.startsWith("return "))
099: expr = "return " + expr;
100: return parser.parse(expr);
101: }
102:
103: /**
104: * Resets the internal code store
105: */
106: public void reset() {
107: code.reset();
108: parser.reset();
109: }
110:
111: /**
112: * Continues execution from current point - only really
113: * useful in a document processing application where you may
114: * wish to add code, execute, add some more code..etc..
115: *@return any return value of the script's execution (will be one of
116: *FScript's supported type objects, Integer,String,Double)
117: */
118: public Object cont() throws IOException, FSException {
119: if (code.getCurLine() == 0) {
120: return run();
121: } else {
122: return parser.parse(code.getCurLine() + 1,
123: code.lineCount() - 1);
124: }
125: }
126:
127: /**
128: * Returns more details on any error states, indicated by
129: * FSExceptions.
130: * @return String, see below <br>
131: * s[0]=the error text <BR>
132: * s[1]=the line number <BR>
133: * s[2]=the line text <BR>
134: * s[3]=the current token <BR>
135: * s[4]=a variable dump (current scope) <BR>
136: * s[5]=a global variable dump (only if currnent scope is not global <BR>
137: */
138: public String[] getError() {
139: return parser.getError();
140: }
141:
142: /**
143: * Override this method to allow external access to variables
144: * in your code.
145: * @param name the name of the variable the parser is requesting
146: * e.g
147: * add this...
148: * <br>
149: * if (name.equals("one") { return new Integer(1) }
150: * <br>
151: * to allow the code
152: * <br>
153: * a=one
154: * <br>
155: * to work in FScript
156: * @return Object - currently expected to be String or Integer
157: */
158: public Object getVar(String name) throws FSException {
159: throw new FSUnsupportedException(name);
160: }
161:
162: /**
163: * Override this method to allow external access to variables
164: * in your code.
165: *<p>As getVar(String name) but allows an index variable to be
166: *passed so code such as :
167: * name=list[2]
168: * is possible
169: * @param name the name of the variable the parser is requesting
170: * @return Object - currently expected to be String, Integer or Double
171: */
172: public Object getVar(String name, Object index) throws FSException {
173: throw new FSUnsupportedException(name);
174: }
175:
176: /**
177: *Entry point for parser (checks against extensions)
178: **/
179: Object getVarEntry(String name, Object index) throws FSException {
180: int n;
181:
182: for (n = 0; n < extensions.size(); n++) {
183: FSExtension extension = (FSExtension) extensions.get(n);
184:
185: try {
186: if (index == null) {
187: return extension.getVar(name);
188: } else {
189: return extension.getVar(name, index);
190: }
191:
192: } catch (FSUnsupportedException e) {
193: //Do nothing continue looping through extensions
194: }
195: }
196:
197: //make call to (hopefully) subclass
198: if (index == null) {
199: return getVar(name);
200: } else {
201: return getVar(name, index);
202: }
203:
204: }
205:
206: /**
207: * Logical inverse of getVar
208: * @param name the variable name
209: * @param value the value to set it to
210: */
211: public void setVar(String name, Object value) throws FSException {
212: throw new FSUnsupportedException(name);
213: }
214:
215: /**
216: * Logical inverse of getVar (with index)
217: * @param name the variable name
218: * @param index the index into the 'array'
219: * @param value the value to set it to
220: */
221: public void setVar(String name, Object index, Object value)
222: throws FSException {
223: throw new FSUnsupportedException(name);
224: }
225:
226: /**
227: *Entry point for parser (checks against extensions)
228: **/
229: void setVarEntry(String name, Object index, Object value)
230: throws FSException {
231:
232: int n;
233: boolean handled = false;
234:
235: for (n = 0; n < extensions.size(); n++) {
236: FSExtension extension = (FSExtension) extensions.get(n);
237:
238: try {
239: if (index == null) {
240: extension.setVar(name, value);
241: handled = true;
242: } else {
243: extension.setVar(name, index, value);
244: handled = true;
245: }
246:
247: } catch (FSUnsupportedException e) {
248: //Do nothing continue looping through extensions
249: }
250: }
251:
252: //make call to (hopefully) subclass
253: if (!handled) {
254: setVar(name, value);
255: }
256:
257: }
258:
259: /**
260: * Override this call to implement custom functions
261: * See the BasicIO class for an example
262: *
263: * @param name the function name
264: * @param params an ArrayList of parameter values
265: * @return an Object, currently expected to be Integer or String
266: */
267: public Object callFunction(String name, ArrayList params)
268: throws FSException {
269: throw new FSUnsupportedException(name);
270: }
271:
272: /**
273: *Entry point for parser (checks against extensions)
274: **/
275: Object callFunctionEntry(String name, ArrayList params)
276: throws FSException {
277:
278: int n;
279:
280: for (n = 0; n < extensions.size(); n++) {
281: FSExtension extension = (FSExtension) extensions.get(n);
282:
283: try {
284: return extension.callFunction(name, params);
285: } catch (FSUnsupportedException e) {
286: //Do nothing continue looping through extensions
287: }
288: }
289:
290: //make call to (hopefully) subclass
291:
292: return callFunction(name, params);
293: }
294:
295: /**
296: *Sets a variable in script space = the value passed in - the variable
297: *must be have the correct type - note that if the varialble is not defined in the
298: *script, calls will be made to subclass setVar methods - therefore this method
299: *should be used with caution from within an overriden setVar.
300: *@param name the name of the variable
301: *@param value the value to set variable to (String,Integer)*/
302: public final void setScriptVar(String name, Object value)
303: throws FSException {
304: parser.setVar(name, value);
305: }
306:
307: /**
308: *Gets a variable in script space note that if the varialble is not defined in the
309: *script, calls will be made to subclass getVar methods - therefore this method
310: *should be used with caution from within an overriden getVar.
311: *@param name the name of the variable
312: *@return the value of the variable (String,Integer)*/
313: public final Object getScriptVar(String name) throws FSException {
314: return parser.getVar(name);
315: }
316:
317: /**Calls a function in the script - note that if the function is not defined calls
318: *will be made to the subclass callFunction methods - therefore this method should
319: *be used with caution from within an overriden callFunction.
320: *@param name the name of the function
321: *@param params the parameters to pass (must be correct type and number)
322: *@return the return value of the function (String,Integer)
323: */
324: public final Object callScriptFunction(String name, ArrayList params)
325: throws IOException, FSException {
326: return parser.callFunction(name, params);
327: }
328:
329: /**
330: * get the current context (executed line, variables etc)
331: * @return
332: */
333: public String getContext() {
334: return parser.getContext();
335: }
336:
337: }
|