001: /*
002: [The "BSD licence"]
003: Copyright (c) 2005-2006 Terence Parr
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011: 2. Redistributions in binary form must reproduce the above copyright
012: notice, this list of conditions and the following disclaimer in the
013: documentation and/or other materials provided with the distribution.
014: 3. The name of the author may not be used to endorse or promote products
015: derived from this software without specific prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
018: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
021: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028: package org.antlr.test;
029:
030: import junit.framework.TestCase;
031: import org.antlr.Tool;
032: import org.antlr.stringtemplate.StringTemplate;
033: import org.antlr.tool.ErrorManager;
034: import org.antlr.tool.Message;
035:
036: import java.io.*;
037: import java.util.ArrayList;
038: import java.util.List;
039:
040: public abstract class BaseTest extends TestCase {
041:
042: public static final String jikes = null;//"/usr/bin/jikes";
043: public static final String pathSep = System
044: .getProperty("path.separator");
045: public static final String CLASSPATH = System
046: .getProperty("java.class.path");
047: public static final String tmpdir = new File(System
048: .getProperty("java.io.tmpdir"), "antlr3").getAbsolutePath();
049:
050: /** If error during execution, store stderr here */
051: protected String stderr;
052:
053: protected Tool newTool() {
054: Tool tool = new Tool();
055: tool.setOutputDirectory(tmpdir);
056: return tool;
057: }
058:
059: protected boolean compile(String fileName) {
060: String compiler = "javac";
061: String classpathOption = "-classpath";
062:
063: if (jikes != null) {
064: compiler = jikes;
065: classpathOption = "-bootclasspath";
066: }
067:
068: String[] args = new String[] { compiler, "-d", tmpdir,
069: classpathOption, tmpdir + pathSep + CLASSPATH,
070: tmpdir + "/" + fileName };
071: String cmdLine = compiler + " -d " + tmpdir + " "
072: + classpathOption + " " + tmpdir + pathSep + CLASSPATH
073: + " " + fileName;
074: //System.out.println("compile: "+cmdLine);
075: File outputDir = new File(tmpdir);
076: try {
077: Process process = Runtime.getRuntime().exec(args, null,
078: outputDir);
079: StreamVacuum stdout = new StreamVacuum(process
080: .getInputStream());
081: StreamVacuum stderr = new StreamVacuum(process
082: .getErrorStream());
083: stdout.start();
084: stderr.start();
085: process.waitFor();
086: if (stdout.toString().length() > 0) {
087: System.err.println("compile stderr from: " + cmdLine);
088: System.err.println(stdout);
089: }
090: if (stderr.toString().length() > 0) {
091: System.err.println("compile stderr from: " + cmdLine);
092: System.err.println(stderr);
093: }
094: int ret = process.exitValue();
095: return ret == 0;
096: } catch (Exception e) {
097: System.err.println("can't exec compilation");
098: e.printStackTrace(System.err);
099: return false;
100: }
101: }
102:
103: /** Return true if all is ok, no errors */
104: protected boolean antlr(String fileName, String grammarFileName,
105: String grammarStr, boolean debug) {
106: boolean allIsWell = true;
107: mkdir(tmpdir);
108: writeFile(tmpdir, fileName, grammarStr);
109: try {
110: final List options = new ArrayList();
111: if (debug) {
112: options.add("-debug");
113: }
114: options.add("-o");
115: options.add(tmpdir);
116: options.add("-lib");
117: options.add(tmpdir);
118: options.add(new File(tmpdir, grammarFileName).toString());
119: final String[] optionsA = new String[options.size()];
120: options.toArray(optionsA);
121: final ErrorQueue equeue = new ErrorQueue();
122: ErrorManager.setErrorListener(equeue);
123: Tool antlr = new Tool(optionsA);
124: antlr.process();
125: if (equeue.errors.size() > 0) {
126: allIsWell = false;
127: System.err.println("antlr reports errors from "
128: + options);
129: for (int i = 0; i < equeue.errors.size(); i++) {
130: Message msg = (Message) equeue.errors.get(i);
131: System.err.println(msg);
132: }
133: }
134: } catch (Exception e) {
135: allIsWell = false;
136: System.err.println("problems building grammar: " + e);
137: e.printStackTrace(System.err);
138: }
139: return allIsWell;
140: }
141:
142: protected String execParser(String grammarFileName,
143: String grammarStr, String parserName, String lexerName,
144: String startRuleName, String input, boolean debug) {
145: eraseFiles(".class");
146: eraseFiles(".java");
147:
148: rawGenerateAndBuildRecognizer(grammarFileName, grammarStr,
149: parserName, lexerName, debug);
150: writeFile(tmpdir, "input", input);
151: boolean parserBuildsTrees = grammarStr.indexOf("output=AST") >= 0
152: || grammarStr.indexOf("output = AST") >= 0;
153: boolean parserBuildsTemplate = grammarStr
154: .indexOf("output=template") >= 0
155: || grammarStr.indexOf("output = template") >= 0;
156: return rawExecRecognizer(parserName, null, lexerName,
157: startRuleName, null, parserBuildsTrees,
158: parserBuildsTemplate, debug);
159: }
160:
161: protected String execTreeParser(String parserGrammarFileName,
162: String parserGrammarStr, String parserName,
163: String treeParserGrammarFileName,
164: String treeParserGrammarStr, String treeParserName,
165: String lexerName, String parserStartRuleName,
166: String treeParserStartRuleName, String input) {
167: return execTreeParser(parserGrammarFileName, parserGrammarStr,
168: parserName, treeParserGrammarFileName,
169: treeParserGrammarStr, treeParserName, lexerName,
170: parserStartRuleName, treeParserStartRuleName, input,
171: false);
172: }
173:
174: protected String execTreeParser(String parserGrammarFileName,
175: String parserGrammarStr, String parserName,
176: String treeParserGrammarFileName,
177: String treeParserGrammarStr, String treeParserName,
178: String lexerName, String parserStartRuleName,
179: String treeParserStartRuleName, String input, boolean debug) {
180: eraseFiles(".class");
181: eraseFiles(".java");
182:
183: // build the parser
184: rawGenerateAndBuildRecognizer(parserGrammarFileName,
185: parserGrammarStr, parserName, lexerName, debug);
186:
187: // build the tree parser
188: rawGenerateAndBuildRecognizer(treeParserGrammarFileName,
189: treeParserGrammarStr, treeParserName, lexerName, debug);
190:
191: writeFile(tmpdir, "input", input);
192:
193: boolean parserBuildsTrees = parserGrammarStr
194: .indexOf("output=AST") >= 0;
195: boolean parserBuildsTemplate = parserGrammarStr
196: .indexOf("output=template") >= 0;
197:
198: return rawExecRecognizer(parserName, treeParserName, lexerName,
199: parserStartRuleName, treeParserStartRuleName,
200: parserBuildsTrees, parserBuildsTemplate, debug);
201: }
202:
203: /** Return true if all is well */
204: protected boolean rawGenerateAndBuildRecognizer(
205: String grammarFileName, String grammarStr,
206: String parserName, String lexerName, boolean debug) {
207: boolean allIsWell = antlr(grammarFileName, grammarFileName,
208: grammarStr, debug);
209: if (lexerName != null) {
210: boolean ok;
211: if (parserName != null) {
212: ok = compile(parserName + ".java");
213: if (!ok) {
214: allIsWell = false;
215: }
216: }
217: ok = compile(lexerName + ".java");
218: if (!ok) {
219: allIsWell = false;
220: }
221: } else {
222: boolean ok = compile(parserName + ".java");
223: if (!ok) {
224: allIsWell = false;
225: }
226: }
227: return allIsWell;
228: }
229:
230: protected String rawExecRecognizer(String parserName,
231: String treeParserName, String lexerName,
232: String parserStartRuleName, String treeParserStartRuleName,
233: boolean parserBuildsTrees, boolean parserBuildsTemplate,
234: boolean debug) {
235: if (parserBuildsTrees) {
236: writeTreeTestFile(parserName, treeParserName, lexerName,
237: parserStartRuleName, treeParserStartRuleName, debug);
238: } else if (parserBuildsTemplate) {
239: writeTemplateTestFile(parserName, lexerName,
240: parserStartRuleName, debug);
241: } else {
242: writeTestFile(parserName, lexerName, parserStartRuleName,
243: debug);
244: }
245:
246: compile("Test.java");
247: try {
248: String[] args = new String[] { "java", "-classpath",
249: CLASSPATH + pathSep + tmpdir, "Test",
250: new File(tmpdir, "input").getAbsolutePath() };
251: String cmdLine = "java -classpath " + CLASSPATH + pathSep
252: + tmpdir + " Test "
253: + new File(tmpdir, "input").getAbsolutePath();
254: //System.out.println("execParser: "+cmdLine);
255: this .stderr = null;
256: Process process = Runtime.getRuntime().exec(args, null,
257: new File(tmpdir));
258: StreamVacuum stdoutVacuum = new StreamVacuum(process
259: .getInputStream());
260: StreamVacuum stderrVacuum = new StreamVacuum(process
261: .getErrorStream());
262: stdoutVacuum.start();
263: stderrVacuum.start();
264: process.waitFor();
265: stdoutVacuum.join();
266: stderrVacuum.join();
267: String output = null;
268: output = stdoutVacuum.toString();
269: if (stderrVacuum.toString().length() > 0) {
270: this .stderr = stderrVacuum.toString();
271: System.err.println("exec parser stderrVacuum: "
272: + stderrVacuum);
273: }
274: return output;
275: } catch (Exception e) {
276: System.err.println("can't exec parser");
277: e.printStackTrace(System.err);
278: }
279: return null;
280: }
281:
282: public static class StreamVacuum implements Runnable {
283: StringBuffer buf = new StringBuffer();
284: BufferedReader in;
285: Thread sucker;
286:
287: public StreamVacuum(InputStream in) {
288: this .in = new BufferedReader(new InputStreamReader(in));
289: }
290:
291: public void start() {
292: sucker = new Thread(this );
293: sucker.start();
294: }
295:
296: public void run() {
297: try {
298: String line = in.readLine();
299: while (line != null) {
300: buf.append(line);
301: buf.append('\n');
302: line = in.readLine();
303: }
304: } catch (IOException ioe) {
305: System.err.println("can't read output from process");
306: }
307: }
308:
309: /** wait for the thread to finish */
310: public void join() throws InterruptedException {
311: sucker.join();
312: }
313:
314: public String toString() {
315: return buf.toString();
316: }
317: }
318:
319: protected void writeFile(String dir, String fileName, String content) {
320: try {
321: File f = new File(dir, fileName);
322: FileWriter w = new FileWriter(f);
323: BufferedWriter bw = new BufferedWriter(w);
324: bw.write(content);
325: bw.close();
326: w.close();
327: } catch (IOException ioe) {
328: System.err.println("can't write file");
329: ioe.printStackTrace(System.err);
330: }
331: }
332:
333: protected void mkdir(String dir) {
334: File f = new File(dir);
335: f.mkdirs();
336: }
337:
338: protected void writeTestFile(String parserName, String lexerName,
339: String parserStartRuleName, boolean debug) {
340: StringTemplate outputFileST = new StringTemplate(
341: "import org.antlr.runtime.*;\n"
342: + "import org.antlr.runtime.tree.*;\n"
343: + "import org.antlr.runtime.debug.*;\n"
344: + "\n"
345: + "class Profiler2 extends Profiler {\n"
346: + " public void terminate() { ; }\n"
347: + "}\n"
348: + "public class Test {\n"
349: + " public static void main(String[] args) throws Exception {\n"
350: + " CharStream input = new ANTLRFileStream(args[0]);\n"
351: + " $lexerName$ lex = new $lexerName$(input);\n"
352: + " CommonTokenStream tokens = new CommonTokenStream(lex);\n"
353: + " $createParser$\n"
354: + " parser.$parserStartRuleName$();\n"
355: + " }\n" + "}");
356: StringTemplate createParserST = new StringTemplate(
357: " Profiler2 profiler = new Profiler2();\n"
358: + " $parserName$ parser = new $parserName$(tokens,profiler);\n"
359: + " profiler.setParser(parser);\n");
360: if (!debug) {
361: createParserST = new StringTemplate(
362: " $parserName$ parser = new $parserName$(tokens);\n");
363: }
364: outputFileST.setAttribute("createParser", createParserST);
365: outputFileST.setAttribute("parserName", parserName);
366: outputFileST.setAttribute("lexerName", lexerName);
367: outputFileST.setAttribute("parserStartRuleName",
368: parserStartRuleName);
369: writeFile(tmpdir, "Test.java", outputFileST.toString());
370: }
371:
372: protected void writeTreeTestFile(String parserName,
373: String treeParserName, String lexerName,
374: String parserStartRuleName, String treeParserStartRuleName,
375: boolean debug) {
376: StringTemplate outputFileST = new StringTemplate(
377: "import org.antlr.runtime.*;\n"
378: + "import org.antlr.runtime.tree.*;\n"
379: + "import org.antlr.runtime.debug.*;\n"
380: + "\n"
381: + "class Profiler2 extends Profiler {\n"
382: + " public void terminate() { ; }\n"
383: + "}\n"
384: + "public class Test {\n"
385: + " public static void main(String[] args) throws Exception {\n"
386: + " CharStream input = new ANTLRFileStream(args[0]);\n"
387: + " $lexerName$ lex = new $lexerName$(input);\n"
388: + " TokenRewriteStream tokens = new TokenRewriteStream(lex);\n"
389: + " $createParser$\n"
390: + " $parserName$.$parserStartRuleName$_return r = parser.$parserStartRuleName$();\n"
391: + " $if(!treeParserStartRuleName)$\n"
392: + " if ( r.tree!=null )\n"
393: + " System.out.println(((Tree)r.tree).toStringTree());\n"
394: + " $else$\n"
395: + " CommonTreeNodeStream nodes = new CommonTreeNodeStream((Tree)r.tree);\n"
396: + " nodes.setTokenStream(tokens);\n"
397: + " $treeParserName$ walker = new $treeParserName$(nodes);\n"
398: + " walker.$treeParserStartRuleName$();\n"
399: + " $endif$\n" + " }\n" + "}");
400: StringTemplate createParserST = new StringTemplate(
401: " Profiler2 profiler = new Profiler2();\n"
402: + " $parserName$ parser = new $parserName$(tokens,profiler);\n"
403: + " profiler.setParser(parser);\n");
404: if (!debug) {
405: createParserST = new StringTemplate(
406: " $parserName$ parser = new $parserName$(tokens);\n");
407: }
408: outputFileST.setAttribute("createParser", createParserST);
409: outputFileST.setAttribute("parserName", parserName);
410: outputFileST.setAttribute("treeParserName", treeParserName);
411: outputFileST.setAttribute("lexerName", lexerName);
412: outputFileST.setAttribute("parserStartRuleName",
413: parserStartRuleName);
414: outputFileST.setAttribute("treeParserStartRuleName",
415: treeParserStartRuleName);
416: writeFile(tmpdir, "Test.java", outputFileST.toString());
417: }
418:
419: protected void writeTemplateTestFile(String parserName,
420: String lexerName, String parserStartRuleName, boolean debug) {
421: StringTemplate outputFileST = new StringTemplate(
422: "import org.antlr.runtime.*;\n"
423: + "import org.antlr.stringtemplate.*;\n"
424: + "import org.antlr.stringtemplate.language.*;\n"
425: + "import org.antlr.runtime.debug.*;\n"
426: + "import java.io.*;\n"
427: + "\n"
428: + "class Profiler2 extends Profiler {\n"
429: + " public void terminate() { ; }\n"
430: + "}\n"
431: + "public class Test {\n"
432: + " static String templates =\n"
433: + " \"group test;\"+"
434: + " \"foo(x,y) ::= \\\"<x> <y>\\\"\";\n"
435: + " static StringTemplateGroup group ="
436: + " new StringTemplateGroup(new StringReader(templates),"
437: + " AngleBracketTemplateLexer.class);"
438: + " public static void main(String[] args) throws Exception {\n"
439: + " CharStream input = new ANTLRFileStream(args[0]);\n"
440: + " $lexerName$ lex = new $lexerName$(input);\n"
441: + " CommonTokenStream tokens = new CommonTokenStream(lex);\n"
442: + " $createParser$\n"
443: + " parser.setTemplateLib(group);\n"
444: + " $parserName$.$parserStartRuleName$_return r = parser.$parserStartRuleName$();\n"
445: + " if ( r.st!=null )\n"
446: + " System.out.print(r.st.toString());\n"
447: + " else\n"
448: + " System.out.print(\"\");\n"
449: + " }\n" + "}");
450: StringTemplate createParserST = new StringTemplate(
451: " Profiler2 profiler = new Profiler2();\n"
452: + " $parserName$ parser = new $parserName$(tokens,profiler);\n"
453: + " profiler.setParser(parser);\n");
454: if (!debug) {
455: createParserST = new StringTemplate(
456: " $parserName$ parser = new $parserName$(tokens);\n");
457: }
458: outputFileST.setAttribute("createParser", createParserST);
459: outputFileST.setAttribute("parserName", parserName);
460: outputFileST.setAttribute("lexerName", lexerName);
461: outputFileST.setAttribute("parserStartRuleName",
462: parserStartRuleName);
463: writeFile(tmpdir, "Test.java", outputFileST.toString());
464: }
465:
466: protected void eraseFiles(final String filesEndingWith) {
467: File tmpdirF = new File(tmpdir);
468: String[] files = tmpdirF.list();
469: for (int i = 0; files != null && i < files.length; i++) {
470: if (files[i].endsWith(filesEndingWith)) {
471: new File(tmpdir + "/" + files[i]).delete();
472: }
473: }
474: }
475:
476: public String getFirstLineOfException() {
477: if (this .stderr == null) {
478: return null;
479: }
480: String[] lines = this .stderr.split("\n");
481: String prefix = "Exception in thread \"main\" ";
482: return lines[0].substring(prefix.length(), lines[0].length());
483: }
484: }
|