001: // This file is part of KeY - Integrated Deductive Software Design
002: // Copyright (C) 2001-2005 Universitaet Karlsruhe, Germany
003: // Universitaet Koblenz-Landau, Germany
004: // Chalmers University of Technology, Sweden
005: //
006: // The KeY system is protected by the GNU General Public License.
007: // See LICENSE.TXT for details.
008: //
009:
010: /**
011: * @author Kristofer Johannisson and Hans-Joachim Daniels (daniels@ira.uka.de)
012: */package de.uka.ilkd.key.ocl.gf;
013:
014: import java.io.*;
015: import java.util.Collection;
016: import java.util.Iterator;
017: import java.util.Vector;
018: import java.util.logging.Level;
019: import java.util.logging.Logger;
020:
021: import javax.swing.ProgressMonitor;
022:
023: import de.uka.ilkd.key.casetool.UMLOCLModel;
024: import de.uka.ilkd.key.proof.mgt.JavaModelMethod;
025:
026: /**
027: * control object interfacing KeY with GF.
028: * Saves the editor from knowing, that KeY exists
029: */
030: public abstract class GFinterface {
031: public final static String gfBinaryCmd = "gf";
032: public final static String u2gfBinaryCmd = "umltypes2gf";
033: public final static String modelModulName = "FromUMLTypes";
034: protected final static String modelinfoUmltypesFilename = "modelinfo.umltypes";
035: /**
036: * get's defined in subclass @see TogetherGFInterface.
037: * Contains the place where modelinfo.umltypes is put
038: */
039: public String modelInfoUmltypes;
040:
041: private static TempGrammarFiles tgf;
042: protected static Logger logger = Logger.getLogger(GFinterface.class
043: .getName());
044:
045: final static boolean AUTO_GENERATE = true; // automatically generate grammars before starting editor
046: /**
047: * get's defined in subclass @see TogetherGFInterface.
048: */
049: protected UMLOCLModel model;
050: protected Collection fromObject;
051: protected Collection inOCL;
052: protected Collection unknownAdded;
053:
054: /**
055: * path to the Together project, get's written in subclass
056: */
057: protected String projectRoot;
058:
059: /**
060: * Creates a new temporary directory and copies the grammars
061: * in a subdirectory called grammars2 of it.
062: * @return the location of the created grammars2 directory
063: */
064: private String copyGrammars() {
065: if (tgf == null) { // only copy if necessary
066: try {
067: tgf = new TempGrammarFiles();
068: } catch (IOException e) {
069: System.err.println("Could not copy GF OCL grammars.");
070: System.err.println("e.getLocalizedMessage(): "
071: + e.getLocalizedMessage());
072: System.err.println("e.toString(): " + e);
073: System.err.println("stacktrace: ");
074: System.err.println(e.getStackTrace().toString());
075: // e.printStackTrace(System.err);
076: // Debug.out(e);
077: return null;
078: }
079: }
080: return tgf.path2grammars2();
081: }
082:
083: /**
084: * Starts the GF editor for OCL for editing a class invariant
085: * @param classname The name of the class whose invariant should be edited
086: * @param pack the package of the class whose invariant should be edited
087: * @param ocl the OCL invariant
088: * @param cci a special callback class, must be properly initialized
089: * @param pm to monitor the loading progress. May be null
090: * @param absFromTogether The abstract syntax tree saved as a JavaDoc
091: * from previous runs
092: * @return message to Together (only if something went wrong?)
093: */
094: public String editClassInvariant(String classname, String pack,
095: String ocl, CallbackClassInv cci, ProgressMonitor pm,
096: String absFromTogether) {
097: Utils.tickProgress(pm, 2340,
098: "Construction the class name for GF");
099: if (logger.isLoggable(Level.FINER)) {
100: logger.finer("previous invariant is: '" + ocl + "'");
101: }
102: //Qualifying invC mit 'core.' is sth. the current GF does not like
103: String gfClassName = constructClassNameForGF(classname, pack,
104: true)
105: + " (\\this -> invCt ?)";
106:
107: Utils.tickProgress(pm, 2350,
108: "Copying grammars to temporary directory");
109: String grammarsDir = copyGrammars();
110: Utils.tickProgress(pm, 3430, "Creating model information");
111: createModelinfo();
112: Utils.tickProgress(pm, 3600, "generating grammars");
113: if (!callUmltypes2gf(grammarsDir, false)) {
114: return "an error occurred";
115: }
116: Utils.tickProgress(pm, 3910,
117: "Constructing abstract syntax tree");
118: String abs = constructAbs("inv: " + ocl, grammarsDir, pack,
119: classname);
120: if ("".equals(abs)) {
121: //seemingly, either sth. unparsable or nothing
122: //was saved as real OCL. So try if sth. was saved as abstract
123: if (absFromTogether != null) {
124: abs = absFromTogether;
125: }
126: }
127:
128: Utils.tickProgress(pm, 5150, "Calling the GF editor");
129: String[] call2gf = constructCallToGF(grammarsDir);
130: cci.setGrammarsDir(grammarsDir);
131: GFEditor2.mainConstraint(call2gf, cci, abs, gfClassName, pm);
132: return ""; // all is well
133: }
134:
135: /** Start GF editor for editing pre-/postcondition of a method/operation
136: * @param classname the name of class of the operation
137: * @param pack the name of the package the class is in
138: * @param opersig signature of the operation
139: * @param pre string containg OCL precondition (currently ignored)
140: * @param post string containg OCL postcondition (currently ignored)
141: * @param isQuery if the method is a query
142: * @param pm to monitor the loading progress. May be null
143: * @param absFromTogether The abstract syntax tree saved as a JavaDoc
144: * from previous runs
145: * @return message to Together (if something went wrong)
146: */
147: public String editPrePost(String classname, String pack,
148: String opersig, String pre, String post,
149: CallbackPrePost cpp, boolean isQuery, ProgressMonitor pm,
150: String absFromTogether) {
151: Utils.tickProgress(pm, 2340,
152: "Construction the operation's name for GF");
153: if (logger.isLoggable(Level.FINER)) {
154: logger.finer("previous precondition is : '" + pre + "'");
155: logger.finer("previous postcondition is: '" + post + "'");
156: }
157: Vector paramNames = new Vector();
158:
159: // Qualifying invC mit 'core.' is sth. the current GF does not like
160: StringBuffer gfOperTree = new StringBuffer(
161: constructOperNameForGF(classname, pack, opersig,
162: paramNames, isQuery));
163: if (logger.isLoggable(Level.FINER)) {
164: logger.finer("GF fun name: " + gfOperTree);
165: }
166: gfOperTree.append(" (\\this");
167:
168: for (Iterator it = paramNames.iterator(); it.hasNext();) {
169: gfOperTree.append(",").append(it.next().toString());
170: }
171: gfOperTree.append(" -> prepostCt ? ? )");
172: Utils.tickProgress(pm, 2350,
173: "Copying grammars to temporary directory");
174: String grammarsDir = copyGrammars();
175:
176: Utils.tickProgress(pm, 3430, "Creating model information");
177: createModelinfo();
178: Utils.tickProgress(pm, 3600, "generating grammars");
179: if (!callUmltypes2gf(grammarsDir, false)) {
180: return "an error occurred";
181: }
182: Utils.tickProgress(pm, 3910,
183: "Constructing abstract syntax tree");
184: String oclConstraint = "";
185: if (pre != null && !("".equals(pre))) {
186: oclConstraint = "pre: " + pre + "\n";
187: }
188: if (post != null && !("".equals(post))) {
189: oclConstraint = oclConstraint + "post: " + post;
190: }
191: String abs = constructAbs(oclConstraint, grammarsDir, pack,
192: classname + "::" + opersig);
193:
194: if ("".equals(abs)) {
195: //seemingly, either sth. unparsable or nothing
196: //was saved as real OCL. So try if sth. was saved as abstract
197: if (absFromTogether != null) {
198: abs = absFromTogether;
199: }
200: }
201: if ("".equals(abs))
202: return "Failed";
203:
204: Utils.tickProgress(pm, 5150, "Calling the GF editor");
205:
206: if (logger.isLoggable(Level.FINE)) {
207: logger.fine("abs: '" + abs + "'");
208: }
209: String[] call2gf = constructCallToGF(grammarsDir);
210:
211: cpp.setGrammarsDir(grammarsDir);
212: GFEditor2.mainConstraint(call2gf, cpp, abs, gfOperTree
213: .toString(), pm);
214:
215: return ""; // everything should be OK
216: }
217:
218: /**
219: * puts the context in front of ocl. Not very fancy
220: * @param ocl the OCL constraint including inv: respectively pre: ... post:
221: * @param context either the class for inv: or the operation
222: * including the class for pre: ... post: .
223: * The package is not needed, that get's wrapped around the context.
224: * @return just the concatenation of context, $context and OCL
225: */
226: private String setupContext(String ocl, String context) {
227: String result = "context " + context + "\n" + ocl;
228: if (logger.isLoggable(Level.FINER)) {
229: logger.finer(result);
230: }
231: return result;
232: }
233:
234: /**
235: * calls ocl2nl to produce a GF abstract syntax tree
236: * @param ocl the actual OCL constraint including inv:
237: * respectively pre: ... post:
238: * @param grammarsDir the temp directory where the GF grammars are stored
239: * @param pack the package in which the constraint should hold
240: * @param context the context for the constraint, be it the class or
241: * class.operation
242: * @return a GF AST for the constraint, if parsing succeeds, "", if not
243: */
244: private String constructAbs(String ocl, String grammarsDir,
245: String pack, String context) {
246: String abs;
247: if (ocl == null || ocl.trim().equals("inv:")
248: || ocl.trim().equals("pre: \npost:")) {
249: abs = "";
250: } else {
251: File oclFile;
252: try {
253: String toParse = setupContext(ocl, context);
254: toParse = wrapOCLwithPackage(toParse, pack);
255: oclFile = TempGrammarFiles.createOCLtmp(toParse);
256: } catch (IOException e) {
257: System.err.println(e.getLocalizedMessage());
258: e.printStackTrace();
259: return e.getLocalizedMessage();
260: }
261: abs = callOcl2Nl(oclFile, grammarsDir, true, false, "");
262: }
263: return abs;
264: }
265:
266: /**
267: * Puts together the call to GF that is to be executed.
268: * Expects that 'gf' is in the path
269: * @param grammarsDir The directory where the grammars reside
270: * @return the command, ready to be executed
271: */
272: private String[] constructCallToGF(String grammarsDir) {
273: String gfOptions = System.getProperty("key.gfoptions");
274: //OCL has to come last so that the printnames from OCL get read.
275: //If the order is changed, the user would have to change the
276: //menu language to OCL to get that effect. TODO
277: int len = 5 + ("-src".equals(gfOptions) ? 1 : 0);
278: String[] s = new String[len];
279: int i = 0;
280: s[i++] = gfBinaryCmd;
281: if ("-src".equals(gfOptions))
282: s[i++] = "-src";
283: s[i++] = "-java";
284: s[i++] = grammarsDir + File.separator
285: + GFinterface.modelModulName + "Ger.gf";
286: s[i++] = grammarsDir + File.separator
287: + GFinterface.modelModulName + "Eng.gf";
288: s[i++] = grammarsDir + File.separator
289: + GFinterface.modelModulName + "OCL.gf";
290:
291: return s;
292: }
293:
294: /**
295: * produces the fun name for a class with package, that can be used in
296: * the context of the FromUMLTypes grammars
297: * @param classname the name of the class that is to be given a new name.
298: * Is expected without any flavouring, just the class name
299: * @param pack the package of the class that is to be given a new name
300: * in the usual.java.notation
301: * @param constr true iff a trailing _Constr should be appended
302: * @return the GF fun name for the class
303: */
304: private String constructClassNameForGF(final String classname,
305: final String pack, boolean constr) {
306: String result = "";
307: String newPack = "";
308:
309: if (pack == null || pack.equals("")) {
310: newPack = "NOPACKAGE";
311: } else {
312: newPack = pack.replaceAll("[\\.]", "P_");
313: }
314:
315: result = newPack + "P_" + classname + "C";
316: if (constr) {
317: result += "_Constr";
318: }
319: //currently GF does not accept module qualified fun names
320: //result = GFinterface.modelModulName + "." + result;
321: if (logger.isLoggable(Level.FINER)) {
322: logger.finer("constructedGFClassName: " + result);
323: }
324: return result;
325: }
326:
327: /**
328: * produces the GF fun name for a class in the double colon notation.
329: * It maps the OCL predefined types to their GF name, which means,
330: * that one cannot have them without packages, since those OCL types
331: * and the userdefined same name types clash.
332: * @param colonNotation a class name with packages like in
333: * <pre>java::math::BigInteger</pre>
334: * @return the GF fun notation like <pre>javaP_mathP_BigIntegerC</pre> or <pre>Integer</pre>
335: */
336: private String constructClassNameForGF(final String colonNotation) {
337: //String baseName = colonNotation.replaceAll("Sequence \\((.*)\\)","$1");
338:
339: String newName = colonNotation.replaceAll(
340: "Sequence \\((.*)\\)", "Sequence_$1");
341: if (newName.indexOf("::") == -1) {
342: if (logger.isLoggable(Level.FINER)) {
343: logger.finer("transformTypeJava2OCL :"
344: + JavaModelMethod
345: .transformTypeJava2OCL(colonNotation));
346: }
347: if (colonNotation != JavaModelMethod
348: .transformTypeJava2OCL(colonNotation)) {
349: newName = "NOPACKAGEP_" + newName;
350: }
351: newName = newName + "C";
352: } else {
353: newName = newName.replaceAll("::", "P_");
354: newName += "C";
355: }
356: return newName.toString();
357: }
358:
359: /**
360: * transform the given method's representation into that of
361: * @param classname The name of class the method belongs to,
362: * without package information
363: * @param pack the package of this class
364: * @param opersig the fully qualified signature of the method like in
365: * <pre>operation1(ios : java::io::PrintStream, bi : java::math::BigInteger) : java::util::Vector</pre>
366: * @param parameterNames This Vector will be filled with the parameter
367: * names of the operation (Strings)
368: * @param isQuery TODO
369: * @return the fun in GF that belongs to this method, like in
370: * <pre>NOPACKAGEP_CardExceptionC_operation1_javaP_ioP_PrintStreamC_javaP_mathP_BigIntegerC_Oper_Constr</pre>
371: */
372: private String constructOperNameForGF(final String classname,
373: final String pack, final String opersig,
374: final Vector parameterNames, boolean isQuery) {
375: final String clss = constructClassNameForGF(classname, pack,
376: false);
377: final StringBuffer newName = new StringBuffer(clss);
378: newName.append("_");
379: if (logger.isLoggable(Level.FINER)) {
380: logger.finer("opersig: " + opersig);
381: }
382: SigTokenizer st = new SigTokenizer(new StringBuffer(opersig));
383: newName.append(st.operName).append("_");
384: for (Iterator it = st.paramTypes.iterator(); it.hasNext();) {
385: newName.append(constructClassNameForGF((String) it.next()))
386: .append("_");
387: }
388: for (Iterator it = st.paramNames.iterator(); it.hasNext();) {
389: parameterNames.add(it.next());
390: }
391:
392: if (st.retType != null) {
393: parameterNames.add(0, "result");
394: }
395: //String returnType = constructClassNameForGF(st.retType);
396: //logger.finer("return type : '" + returnType + "'");
397: newName.append("Oper_Constr");
398:
399: return newName.toString();
400: }
401:
402: /**
403: * Wraps an OCL statement with a PACKAGE section
404: * @param ocl the OCL statement to be wrapped
405: * @param pack the package name in Java notation
406: * @return the OCL grammar notation, NOPACKAGE if package name is empty
407: */
408: private String wrapOCLwithPackage(final String ocl,
409: final String pack) {
410: if (logger.isLoggable(Level.FINER)) {
411: logger.finer("wrap: pack='" + pack + "' -- ocl='" + ocl
412: + "'");
413: }
414: String oclPackage;
415: if (pack == null || pack.equals("")) {
416: oclPackage = "NOPACKAGE";
417: } else {
418: oclPackage = pack.replaceAll("[::]", "\\.");
419: }
420: String result = "package " + oclPackage + "\n" + ocl
421: + "\nendpackage\n";
422: if (logger.isLoggable(Level.FINER)) {
423: logger.finer("wrapped = '" + result + "'");
424: }
425: return result;
426: }
427:
428: /**
429: * calls the external binary ocl2nl, which is expected to be in the
430: * path and returns the abstract Syntax tree
431: * @param oclFile the file where the ocl constraints are stored.
432: * These get parsed.
433: * @param grammarsDir the path of the directory that contains the
434: * OCL-GF2 grammars
435: * @param generateTree should ocl2nl produce a GF tree instead of NL text?
436: * @param optimize should ocl2nl optimize the output
437: * @param format should be one of {"", "html", "latex"}
438: * @return the abstract syntax tree for GF of the OCL constraints
439: * in oclFile
440: */
441: private String callOcl2Nl(File oclFile, String grammarsDir,
442: boolean generateTree, boolean optimize, String format) {
443:
444: int len = 5 + (generateTree ? 1 : 0) + (optimize ? 1 : 0)
445: + (format.equals("") ? 0 : 1);
446: String[] call = new String[len];
447: int i = 0;
448: call[i++] = "ocl2nl";
449: if (generateTree)
450: call[i++] = "-t";
451: if (optimize)
452: call[i++] = "-o";
453: if (format.equals("html"))
454: call[i++] = "-f html";
455: if (format.equals("latex"))
456: call[i++] = "-f latex";
457: call[i++] = "-p";
458: call[i++] = grammarsDir;
459: call[i++] = modelInfoUmltypes;
460: call[i++] = oclFile.getAbsolutePath();
461:
462: if (logger.isLoggable(Level.FINER)) {
463: logger.finer("call to ocl2nl: '" + call + "'");
464: }
465:
466: String s = "";
467: StringBuffer result = new StringBuffer("");
468:
469: try {
470: Process p = Runtime.getRuntime().exec(call);
471:
472: BufferedReader stdInput = new BufferedReader(
473: new InputStreamReader(p.getInputStream()));
474:
475: BufferedReader stdError = new BufferedReader(
476: new InputStreamReader(p.getErrorStream()));
477:
478: //final String oneConstraint = "[document] ([oneConstraint]"; //old format
479: final String oneConstraint = "%document% (%oneConstraint%";
480: // read the output from the command
481: while ((s = stdInput.readLine()) != null) {
482: if (logger.isLoggable(Level.FINER)) {
483: logger.finer(s);
484: }
485:
486: if (generateTree) {
487: //looks out for %oneConstraint% since the
488: //normal GF output can't be switched of at the
489: //moment
490: int index = s.indexOf(oneConstraint);
491: if (index > -1) {
492: //delete oneConstraint and the corresponding closing bracket
493: result.append(s.substring(index
494: + oneConstraint.length() + 1, s
495: .length() - 1));
496: }
497: } else {
498: result.append(s);
499: }
500: }
501:
502: // read any errors from the attempted command
503:
504: while ((s = stdError.readLine()) != null) {
505: if (!s.trim().equals("")) {
506: System.err.println("Standard error from "
507: + java.util.Arrays.asList(call));
508: System.err.println(s);
509: return "";
510: }
511: }
512: } catch (IOException e) {
513: System.err
514: .println("error calling ocl2nl:" + e.getMessage());
515: return "";
516: }
517:
518: return result.toString();
519: }
520:
521: /**
522: * create the necessary GF grammars from the information in the UML model of
523: * the current project
524: */
525: private void createModelinfo() {
526: if (AUTO_GENERATE) {
527: ModelExporter me = new ModelExporter(model
528: .getUMLOCLClassifiers());
529: me.export(modelInfoUmltypes);
530: }
531: }
532:
533: /**
534: * Takes the modelinfo.umltypes file and generates the GF grammars
535: * based on what's inside this file
536: * @param pathToGrammars The directory where the grammars should be stored
537: * @param inclJava all referenced Java should be represented in the grammars
538: * @return true, if everything worked fine, otherwise false
539: */
540: private boolean callUmltypes2gf(String pathToGrammars,
541: boolean inclJava) {
542: String[] call = new String[] { u2gfBinaryCmd, "-i",
543: pathToGrammars, "-o", pathToGrammars,
544: (inclJava ? "" : "-j"), modelInfoUmltypes };
545: if (logger.isLoggable(Level.FINER)) {
546: logger.finer("call to umltypes2gf: '" + call + "'");
547: }
548:
549: String s = null;
550:
551: try {
552: Process p = Runtime.getRuntime().exec(call);
553:
554: BufferedReader stdInput = new BufferedReader(
555: new InputStreamReader(p.getInputStream()));
556:
557: BufferedReader stdError = new BufferedReader(
558: new InputStreamReader(p.getErrorStream()));
559:
560: // read the output from the command
561:
562: String out = "";
563: while ((s = stdInput.readLine()) != null)
564: out = out + s;
565: if (!"".equals(out.trim())) {
566: System.err
567: .println("Here is the standard out of the command "
568: + java.util.Arrays.asList(call) + ":\n");
569: System.err.println(out);
570: }
571:
572: // read any errors from the attempted command
573:
574: String err = "";
575: while ((s = stdError.readLine()) != null)
576: err = err + s;
577: if (!"".equals(err.trim())) {
578: System.err
579: .println("Here is the standard error of the command "
580: + java.util.Arrays.asList(call) + ":\n");
581: System.err.println(err);
582: return false;
583: }
584:
585: } catch (IOException e) {
586: System.err.println("error calling umltypes2gf:"
587: + e.getMessage());
588: return false;
589: }
590: return true;
591: }
592:
593: /**
594: * translate all OCL specs in a text file to NL
595: * @param format should be either "html" or "latex"
596: */
597: public void ocl2nlExport(File oclFile, File nlFile, String format) {
598: // generate UML model file
599: createModelinfo();
600:
601: // generate grammars
602: String grammarsDir = copyGrammars();
603: if (!callUmltypes2gf(grammarsDir, false)) {
604: System.err
605: .println("ocl2nlExport: grammar generation failed.");
606: return;
607: } else {
608: // call binary ocl2nl, default to HTML
609: if (!(format.equals("html") || format.equals("latex"))) {
610: format = "html";
611: }
612: String nl = callOcl2Nl(oclFile, grammarsDir, false, false,
613: format);
614: // put NL in a file
615: try {
616: PrintWriter out = new PrintWriter(new BufferedWriter(
617: new FileWriter(nlFile)));
618: out.print(nl);
619: out.close();
620: } catch (IOException e) {
621: System.err
622: .println("could not write NL translation of OCL file: "
623: + e.getMessage());
624: }
625: }
626: }
627:
628: }
629:
630: /**
631: * A class that takes an operation's signature and makes the constituents
632: * like name, parameters and their types available in this data structure
633: * @author hdaniels
634: */
635: class SigTokenizer {
636: private final StringBuffer workingsig;
637: /**
638: * the names of the parameters as Strings
639: */
640: public Vector paramNames = new Vector();
641: /**
642: * the types of the parameters in OCL notation as Strings
643: */
644: public Vector paramTypes = new Vector();
645: /**
646: * the return type of the operation, null iff void
647: */
648: public String retType = null;
649: /**
650: * the name of the given operation
651: */
652: public final String operName;
653:
654: /**
655: * lexes the given signature and fills the other fields with
656: * their values
657: * @param sig the operation's signature without package
658: */
659: public SigTokenizer(StringBuffer sig) {
660: this .workingsig = new StringBuffer(sig.toString());
661: int index = workingsig.indexOf("(");
662: operName = workingsig.substring(0, index);
663: workingsig.delete(0, index);
664: while (produceNext()) {
665: }
666: }
667:
668: /**
669: * cuts through the signature and writes the names and types of the
670: * parameters and the type of the result into the respective fields.
671: * Must be called until it returns false
672: * @return true iff sth. of the signature is left to parse
673: */
674: private boolean produceNext() {
675: if (workingsig.charAt(0) == '(') {
676: workingsig.deleteCharAt(0);
677: //first parameter
678: return true;
679: }
680:
681: if (workingsig.charAt(0) == ':') {
682: // return type
683: workingsig.delete(0, 2);
684: retType = workingsig.toString();
685: return false;
686: }
687:
688: int pindex = workingsig.indexOf(", ");
689: if (pindex == -1) {
690: //param) : retType //which exists
691: pindex = workingsig.indexOf(") ");
692: }
693: if (pindex > 0) {
694: //more parameters exist
695: String s = workingsig.substring(0, pindex);
696: nameType(s);
697: workingsig.delete(0, pindex + 2);
698: return true;
699: }
700: if (pindex == 0) {
701: //no more params, but return type
702: workingsig.delete(0, pindex + 2);
703: return true;
704: }
705: //no returntype exists, but last param is Sequence (...)
706: pindex = workingsig.indexOf("))");
707: if (pindex > -1) {
708: //more parameters exist
709: String s = workingsig.substring(0, pindex + 1);
710: nameType(s);
711: workingsig.delete(0, pindex + 2);
712: return false;
713: }
714: //no returntype exists, but last param is no Sequence
715: pindex = workingsig.indexOf(")");
716: if ((pindex > 0) && (pindex == workingsig.length() - 1)) {
717: String s = workingsig.substring(0, pindex);
718: nameType(s);
719: workingsig.delete(0, pindex + 1);
720: return false;
721: }
722: //what remains is a single ')'
723: return false;
724: }
725:
726: /**
727: * takes a pair of parameter name : type and writes both parts
728: * into the two Vector fields
729: * @param myworkingsig the parameter in the form
730: * <pre>parameterName : parameter::type</pre>
731: */
732: private void nameType(String myworkingsig) {
733: int pindex = myworkingsig.indexOf(" : ");
734: String paramName = myworkingsig.substring(0, pindex);
735: paramNames.add(paramName);
736: myworkingsig = myworkingsig.substring(pindex + 3);//delete ' : ' also
737: String paramTypeCN = myworkingsig;
738: paramTypes.add(paramTypeCN);
739: }
740: }
|