Merge pull request #13 from antlr/intermediate-test-generation

Move to new testing mechanism
This commit is contained in:
Terence Parr 2015-06-03 10:44:10 -07:00
commit 345bd14c00
19 changed files with 1627 additions and 218 deletions

View File

@ -49,7 +49,7 @@ public class CSharpTarget extends Target {
@Override
public String getVersion() {
return "4.5"; // crossing fingers that it's close enough.
return "4.5.1"; // crossing fingers that it's close enough.
}
@Override

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestCompositeLexers extends BaseTest {
public class TestCompositeLexers extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -5,7 +5,7 @@ import org.junit.Test;
import org.antlr.v4.test.tool.ErrorQueue;
import org.antlr.v4.tool.Grammar;
public class TestCompositeParsers extends BaseTest {
public class TestCompositeParsers extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestFullContextParsing extends BaseTest {
public class TestFullContextParsing extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestLeftRecursion extends BaseTest {
public class TestLeftRecursion extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
String testSimple(String input) throws Exception {

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestLexerErrors extends BaseTest {
public class TestLexerErrors extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestLexerExec extends BaseTest {
public class TestLexerExec extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestListeners extends BaseTest {
public class TestListeners extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestParseTrees extends BaseTest {
public class TestParseTrees extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestParserErrors extends BaseTest {
public class TestParserErrors extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestParserExec extends BaseTest {
public class TestParserExec extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestSemPredEvalLexer extends BaseTest {
public class TestSemPredEvalLexer extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestSemPredEvalParser extends BaseTest {
public class TestSemPredEvalParser extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -2,7 +2,7 @@ package org.antlr.v4.test.rt.csharp;
import org.junit.Test;
public class TestSets extends BaseTest {
public class TestSets extends org.antlr.v4.test.runtime.csharp.BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?><Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EDC70A11-C4C1-4209-93A6-CCE2B19E8E95}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Antlr4.Test.mono</RootNamespace>
<AssemblyName>Test</AssemblyName>
<StartupObject>Test</StartupObject>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System"/>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs"/>
<Compile Include="Test.cs"/>
<Compile Include="L.cs"/>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets"/>
<ItemGroup>
<ProjectReference Include="Antlr4.Runtime.mono.csproj">
<Project>{E1A46D9D-66CB-46E8-93B0-7FC87299ABEF}</Project>
<Name>Antlr4.Runtime.mono</Name>
</ProjectReference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?><Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EDC70A11-C4C1-4209-93A6-CCE2B19E8E95}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Antlr4.Test.mono</RootNamespace>
<AssemblyName>Test</AssemblyName>
<StartupObject>Test</StartupObject>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System"/>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs"/>
<Compile Include="Test.cs"/>
<Compile Include="L.cs"/>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets"/>
<ItemGroup>
<ProjectReference Include="Antlr4.Runtime.vs2013.csproj">
<Project>{E1A46D9D-66CB-46E8-93B0-7FC87299ABEF}</Project>
<Name>Antlr4.Runtime.vs2013</Name>
</ProjectReference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,28 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle ("Antlr4.Test.mono")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("")]
[assembly: AssemblyProduct ("")]
[assembly: AssemblyCopyright ("ericvergnaud")]
[assembly: AssemblyTrademark ("")]
[assembly: AssemblyCulture ("")]
[assembly: CLSCompliant (true)]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion ("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -0,0 +1,898 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Terence Parr
* Copyright (c) 2012 Sam Harwell
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.v4.test.runtime.csharp;
import org.antlr.v4.Tool;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenSource;
import org.antlr.v4.runtime.WritableToken;
import org.antlr.v4.runtime.misc.Utils;
import org.antlr.v4.test.tool.ErrorQueue;
import org.antlr.v4.tool.ANTLRMessage;
import org.antlr.v4.tool.DefaultToolListener;
import org.antlr.v4.tool.GrammarSemanticsMessage;
import org.junit.Before;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.stringtemplate.v4.ST;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public abstract class BaseTest {
public static final String newline = System.getProperty("line.separator");
public static final String pathSep = System.getProperty("path.separator");
/**
* When the {@code antlr.preserve-test-dir} runtime property is set to
* {@code true}, the temporary directories created by the test run will not
* be removed at the end of the test run, even for tests that completed
* successfully.
*
* <p>
* The default behavior (used in all other cases) is removing the temporary
* directories for all tests which completed successfully, and preserving
* the directories for tests which failed.</p>
*/
public static final boolean PRESERVE_TEST_DIR = Boolean.parseBoolean(System.getProperty("antlr-preserve-csharp-test-dir"));
/**
* The base test directory is the directory where generated files get placed
* during unit test execution.
*
* <p>
* The default value for this property is the {@code java.io.tmpdir} system
* property, and can be overridden by setting the
* {@code antlr.java-test-dir} property to a custom location. Note that the
* {@code antlr.java-test-dir} property directly affects the
* {@link #CREATE_PER_TEST_DIRECTORIES} value as well.</p>
*/
public static final String BASE_TEST_DIR;
/**
* When {@code true}, a temporary directory will be created for each test
* executed during the test run.
*
* <p>
* This value is {@code true} when the {@code antlr.java-test-dir} system
* property is set, and otherwise {@code false}.</p>
*/
public static final boolean CREATE_PER_TEST_DIRECTORIES;
static {
String baseTestDir = System.getProperty("antlr-csharp-test-dir");
boolean perTestDirectories = false;
if (baseTestDir == null || baseTestDir.isEmpty()) {
baseTestDir = System.getProperty("java.io.tmpdir");
perTestDirectories = true;
}
if (!new File(baseTestDir).isDirectory()) {
throw new UnsupportedOperationException("The specified base test directory does not exist: " + baseTestDir);
}
BASE_TEST_DIR = baseTestDir;
CREATE_PER_TEST_DIRECTORIES = perTestDirectories;
}
public String tmpdir = null;
/** If error during parser execution, store stderr here; can't return
* stdout and stderr. This doesn't trap errors from running antlr.
*/
protected String stderrDuringParse;
@org.junit.Rule
public final TestRule testWatcher = new TestWatcher() {
@Override
protected void succeeded(Description description) {
// remove tmpdir if no error.
if (!PRESERVE_TEST_DIR) {
eraseTempDir();
}
}
};
@Before
public void setUp() throws Exception {
if (CREATE_PER_TEST_DIRECTORIES) {
// new output dir for each test
String testDirectory = getClass().getSimpleName() + "-" + System.currentTimeMillis();
tmpdir = new File(BASE_TEST_DIR, testDirectory).getAbsolutePath();
}
else {
tmpdir = new File(BASE_TEST_DIR).getAbsolutePath();
if (!PRESERVE_TEST_DIR && new File(tmpdir).exists()) {
eraseFiles();
}
}
}
protected org.antlr.v4.Tool newTool(String[] args) {
Tool tool = new Tool(args);
return tool;
}
protected Tool newTool() {
org.antlr.v4.Tool tool = new Tool(new String[] {"-o", tmpdir});
return tool;
}
protected String load(String fileName, String encoding)
throws IOException
{
if ( fileName==null ) {
return null;
}
String fullFileName = getClass().getPackage().getName().replace('.', '/') + '/' + fileName;
int size = 65000;
InputStreamReader isr;
InputStream fis = getClass().getClassLoader().getResourceAsStream(fullFileName);
if ( encoding!=null ) {
isr = new InputStreamReader(fis, encoding);
}
else {
isr = new InputStreamReader(fis);
}
try {
char[] data = new char[size];
int n = isr.read(data);
return new String(data, 0, n);
}
finally {
isr.close();
}
}
protected ErrorQueue antlr(String grammarFileName, boolean defaultListener, String... extraOptions) {
final List<String> options = new ArrayList<String>();
Collections.addAll(options, extraOptions);
options.add("-Dlanguage=CSharp");
if ( !options.contains("-o") ) {
options.add("-o");
options.add(tmpdir);
}
if ( !options.contains("-lib") ) {
options.add("-lib");
options.add(tmpdir);
}
if ( !options.contains("-encoding") ) {
options.add("-encoding");
options.add("UTF-8");
}
options.add(new File(tmpdir,grammarFileName).toString());
final String[] optionsA = new String[options.size()];
options.toArray(optionsA);
Tool antlr = newTool(optionsA);
ErrorQueue equeue = new ErrorQueue(antlr);
antlr.addListener(equeue);
if (defaultListener) {
antlr.addListener(new DefaultToolListener(antlr));
}
antlr.processGrammarsOnCommandLine();
if ( !defaultListener && !equeue.errors.isEmpty() ) {
System.err.println("antlr reports errors from "+options);
for (int i = 0; i < equeue.errors.size(); i++) {
ANTLRMessage msg = equeue.errors.get(i);
System.err.println(msg);
}
System.out.println("!!!\ngrammar:");
try {
System.out.println(new String(Utils.readFile(tmpdir+"/"+grammarFileName)));
}
catch (IOException ioe) {
System.err.println(ioe.toString());
}
System.out.println("###");
}
if ( !defaultListener && !equeue.warnings.isEmpty() ) {
System.err.println("antlr reports warnings from "+options);
for (int i = 0; i < equeue.warnings.size(); i++) {
ANTLRMessage msg = equeue.warnings.get(i);
System.err.println(msg);
}
}
return equeue;
}
protected ErrorQueue antlr(String grammarFileName, String grammarStr, boolean defaultListener, String... extraOptions) {
System.out.println("dir "+tmpdir);
mkdir(tmpdir);
writeFile(tmpdir, grammarFileName, grammarStr);
return antlr(grammarFileName, defaultListener, extraOptions);
}
protected String execLexer(String grammarFileName,
String grammarStr,
String lexerName,
String input)
{
return execLexer(grammarFileName, grammarStr, lexerName, input, false);
}
protected String execLexer(String grammarFileName,
String grammarStr,
String lexerName,
String input,
boolean showDFA)
{
boolean success = rawGenerateRecognizer(grammarFileName,
grammarStr,
null,
lexerName);
assertTrue(success);
writeFile(tmpdir, "input", input);
writeLexerTestFile(lexerName, showDFA);
addSourceFiles("Test.cs");
compile();
String output = execTest();
if ( stderrDuringParse!=null && stderrDuringParse.length()>0 ) {
System.err.println(stderrDuringParse);
}
return output;
}
Set<String> sourceFiles = new HashSet<String>();
private void addSourceFiles(String ... files) {
for(String file : files)
this.sourceFiles.add(file);
}
protected String execParser(String grammarFileName,
String grammarStr,
String parserName,
String lexerName,
String startRuleName,
String input, boolean debug)
{
boolean success = rawGenerateRecognizer(grammarFileName,
grammarStr,
parserName,
lexerName,
"-visitor");
assertTrue(success);
writeFile(tmpdir, "input", input);
return rawExecRecognizer(parserName,
lexerName,
startRuleName,
debug);
}
/** Return true if all is well */
protected boolean rawGenerateRecognizer(String grammarFileName,
String grammarStr,
String parserName,
String lexerName,
String... extraOptions)
{
return rawGenerateRecognizer(grammarFileName, grammarStr, parserName, lexerName, false, extraOptions);
}
/** Return true if all is well */
protected boolean rawGenerateRecognizer(String grammarFileName,
String grammarStr,
String parserName,
String lexerName,
boolean defaultListener,
String... extraOptions)
{
ErrorQueue equeue = antlr(grammarFileName, grammarStr, defaultListener, extraOptions);
if (!equeue.errors.isEmpty()) {
return false;
}
List<String> files = new ArrayList<String>();
if ( lexerName!=null ) {
files.add(lexerName+".cs");
}
if ( parserName!=null ) {
files.add(parserName+".cs");
Set<String> optionsSet = new HashSet<String>(Arrays.asList(extraOptions));
String grammarName = grammarFileName.substring(0, grammarFileName.lastIndexOf('.'));
if (!optionsSet.contains("-no-listener")) {
files.add(grammarName+"Listener.cs");
files.add(grammarName+"BaseListener.cs");
}
if (optionsSet.contains("-visitor")) {
files.add(grammarName+"Visitor.cs");
files.add(grammarName+"BaseVisitor.cs");
}
}
addSourceFiles(files.toArray(new String[files.size()]));
return true;
}
protected String rawExecRecognizer(String parserName,
String lexerName,
String parserStartRuleName,
boolean debug)
{
this.stderrDuringParse = null;
if ( parserName==null ) {
writeLexerTestFile(lexerName, false);
}
else {
writeParserTestFile(parserName,
lexerName,
parserStartRuleName,
debug);
}
addSourceFiles("Test.cs");
return execRecognizer();
}
public String execRecognizer() {
compile();
return execTest();
}
public boolean compile() {
try {
if(!createProject())
return false;
if(!buildProject())
return false;
return true;
} catch(Exception e) {
return false;
}
}
private File getTestProjectFile() {
return new File(tmpdir, "Antlr4.Test.mono.csproj");
}
private boolean buildProject() throws Exception {
String msbuild = locateMSBuild();
String[] args = {
msbuild,
"/p:Configuration=Release",
getTestProjectFile().getAbsolutePath()
};
System.err.println("Starting build "+Utils.join(args, " "));
Process process =
Runtime.getRuntime().exec(args, null, new File(tmpdir));
StreamVacuum stdoutVacuum = new StreamVacuum(process.getInputStream());
StreamVacuum stderrVacuum = new StreamVacuum(process.getErrorStream());
stdoutVacuum.start();
stderrVacuum.start();
process.waitFor();
stdoutVacuum.join();
stderrVacuum.join();
if ( stderrVacuum.toString().length()>0 ) {
this.stderrDuringParse = stderrVacuum.toString();
System.err.println("buildProject stderrVacuum: "+ stderrVacuum);
}
return process.exitValue()==0;
}
private String locateMSBuild() {
if(isWindows())
return "\"C:\\Program Files (x86)\\MSBuild\\12.0\\Bin\\MSBuild.exe\"";
else
return locateTool("xbuild");
}
private boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("windows");
}
private String locateExec() {
return new File(tmpdir, "bin/Release/Test.exe").getAbsolutePath();
}
private String locateTool(String tool) {
String[] roots = { "/usr/bin/", "/usr/local/bin/" };
for(String root : roots) {
if(new File(root + tool).exists())
return root + tool;
}
throw new RuntimeException("Could not locate " + tool);
}
public boolean createProject() {
try {
String pack = this.getClass().getPackage().getName().replace(".", "/") + "/";
System.out.println("create project "+pack);
// save AssemblyInfo
InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(pack + "AssemblyInfo.cs");
if ( input==null ) {
System.err.println("Can't find " + pack + "AssemblyInfo.cs as resource");
return false;
}
OutputStream output = new FileOutputStream(new File(tmpdir, "AssemblyInfo.cs").getAbsolutePath());
while(input.available()>0) {
output.write(input.read());
}
output.close();
input.close();
// update project
String projectName = isWindows() ? "Antlr4.Test.vs2013.csproj" : "Antlr4.Test.mono.csproj";
input = Thread.currentThread().getContextClassLoader().getResourceAsStream(pack + projectName);
Document prjXml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input);
// update runtime project reference
String runtimePath = System.getProperty("antlr-csharp-runtime-project");
String runtimeName = isWindows() ? "Antlr4.Runtime.vs2013.csproj" : "Antlr4.Runtime.mono.csproj";
if(runtimePath==null)
runtimePath = "../../antlr4-csharp/runtime/CSharp/Antlr4.Runtime/" + runtimeName;
File projFile = new File(runtimePath);
if(!projFile.exists())
throw new RuntimeException("C# runtime project file not found at:" + projFile.getAbsolutePath());
runtimePath = projFile.getAbsolutePath();
XPathExpression exp = XPathFactory.newInstance().newXPath().compile("/Project/ItemGroup/ProjectReference[@Include='" + runtimeName + "']");
Element node = (Element)exp.evaluate(prjXml, XPathConstants.NODE);
node.setAttribute("Include", runtimePath.replace("/", "\\"));
// update project file list
exp = XPathFactory.newInstance().newXPath().compile("/Project/ItemGroup[Compile/@Include='AssemblyInfo.cs']");
Element group = (Element)exp.evaluate(prjXml, XPathConstants.NODE);
if(group==null)
return false;
// remove existing children
while(group.hasChildNodes())
group.removeChild(group.getFirstChild());
// add AssemblyInfo.cs, not a generated source
sourceFiles.add("AssemblyInfo.cs");
// add files to compile
for(String file : sourceFiles) {
Element elem = group.getOwnerDocument().createElement("Compile");
elem.setAttribute("Include", file);
group.appendChild(elem);
}
// save project
File prjFile = getTestProjectFile();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(prjXml), new StreamResult(prjFile));
return true;
} catch(Exception e) {
e.printStackTrace(System.err);
return false;
}
}
public String execTest() {
try {
String exec = locateExec();
String[] args = isWindows() ?
new String[] { exec, new File(tmpdir, "input").getAbsolutePath() } :
new String[] { "mono", "--runtime=v4.0.30319", exec, new File(tmpdir, "input").getAbsolutePath() };
ProcessBuilder pb = new ProcessBuilder(args);
pb.directory(new File(tmpdir));
Process p = pb.start();
StreamVacuum stdoutVacuum = new StreamVacuum(p.getInputStream());
StreamVacuum stderrVacuum = new StreamVacuum(p.getErrorStream());
stdoutVacuum.start();
stderrVacuum.start();
p.waitFor();
stdoutVacuum.join();
stderrVacuum.join();
String output = stdoutVacuum.toString();
if ( stderrVacuum.toString().length()>0 ) {
this.stderrDuringParse = stderrVacuum.toString();
System.err.println("exec stderrVacuum: "+ stderrVacuum);
}
return output;
}
catch (Exception e) {
System.err.println("can't exec recognizer");
e.printStackTrace(System.err);
}
return null;
}
public void testErrors(String[] pairs, boolean printTree) {
for (int i = 0; i < pairs.length; i+=2) {
String input = pairs[i];
String expect = pairs[i+1];
String[] lines = input.split("\n");
String fileName = getFilenameFromFirstLineOfGrammar(lines[0]);
ErrorQueue equeue = antlr(fileName, input, false);
String actual = equeue.toString(true);
actual = actual.replace(tmpdir + File.separator, "");
System.err.println(actual);
String msg = input;
msg = msg.replace("\n","\\n");
msg = msg.replace("\r","\\r");
msg = msg.replace("\t","\\t");
org.junit.Assert.assertEquals("error in: "+msg,expect,actual);
}
}
public String getFilenameFromFirstLineOfGrammar(String line) {
String fileName = "A" + Tool.GRAMMAR_EXTENSION;
int grIndex = line.lastIndexOf("grammar");
int semi = line.lastIndexOf(';');
if ( grIndex>=0 && semi>=0 ) {
int space = line.indexOf(' ', grIndex);
fileName = line.substring(space+1, semi)+Tool.GRAMMAR_EXTENSION;
}
if ( fileName.length()==Tool.GRAMMAR_EXTENSION.length() ) fileName = "A" + Tool.GRAMMAR_EXTENSION;
return fileName;
}
List<ANTLRMessage> getMessagesOfType(List<ANTLRMessage> msgs, Class<? extends ANTLRMessage> c) {
List<ANTLRMessage> filtered = new ArrayList<ANTLRMessage>();
for (ANTLRMessage m : msgs) {
if ( m.getClass() == c ) filtered.add(m);
}
return filtered;
}
public static class StreamVacuum implements Runnable {
StringBuilder buf = new StringBuilder();
BufferedReader in;
Thread sucker;
public StreamVacuum(InputStream in) {
this.in = new BufferedReader( new InputStreamReader(in) );
}
public void start() {
sucker = new Thread(this);
sucker.start();
}
@Override
public void run() {
try {
String line = in.readLine();
while (line!=null) {
buf.append(line);
buf.append('\n');
line = in.readLine();
}
}
catch (IOException ioe) {
System.err.println("can't read output from process");
}
}
/** wait for the thread to finish */
public void join() throws InterruptedException {
sucker.join();
}
@Override
public String toString() {
return buf.toString();
}
}
protected void checkGrammarSemanticsError(ErrorQueue equeue,
GrammarSemanticsMessage expectedMessage)
throws Exception
{
ANTLRMessage foundMsg = null;
for (int i = 0; i < equeue.errors.size(); i++) {
ANTLRMessage m = equeue.errors.get(i);
if (m.getErrorType()==expectedMessage.getErrorType() ) {
foundMsg = m;
}
}
assertNotNull("no error; "+expectedMessage.getErrorType()+" expected", foundMsg);
assertTrue("error is not a GrammarSemanticsMessage",
foundMsg instanceof GrammarSemanticsMessage);
assertEquals(Arrays.toString(expectedMessage.getArgs()), Arrays.toString(foundMsg.getArgs()));
if ( equeue.size()!=1 ) {
System.err.println(equeue);
}
}
public static class FilteringTokenStream extends CommonTokenStream {
public FilteringTokenStream(TokenSource src) { super(src); }
Set<Integer> hide = new HashSet<Integer>();
@Override
protected boolean sync(int i) {
if (!super.sync(i)) {
return false;
}
Token t = get(i);
if ( hide.contains(t.getType()) ) {
((WritableToken)t).setChannel(Token.HIDDEN_CHANNEL);
}
return true;
}
public void setTokenTypeChannel(int ttype, int channel) {
hide.add(ttype);
}
}
public static void writeFile(String dir, String fileName, String content) {
try {
Utils.writeFile(dir+"/"+fileName, content, "UTF-8");
}
catch (IOException ioe) {
System.err.println("can't write file");
ioe.printStackTrace(System.err);
}
}
protected void mkdir(String dir) {
File f = new File(dir);
f.mkdirs();
}
protected void writeParserTestFile(String parserName,
String lexerName,
String parserStartRuleName,
boolean debug)
{
ST outputFileST = new ST(
"using System;\n" +
"using Antlr4.Runtime;\n" +
"using Antlr4.Runtime.Tree;\n" +
"\n" +
"public class Test {\n" +
" public static void Main(string[] args) {\n" +
" ICharStream input = new AntlrFileStream(args[0]);\n" +
" <lexerName> lex = new <lexerName>(input);\n" +
" CommonTokenStream tokens = new CommonTokenStream(lex);\n" +
" <createParser>\n"+
" parser.BuildParseTree = true;\n" +
" ParserRuleContext tree = parser.<parserStartRuleName>();\n" +
" ParseTreeWalker.Default.Walk(new TreeShapeListener(), tree);\n" +
" }\n" +
"}\n" +
"\n" +
"class TreeShapeListener : IParseTreeListener {\n" +
" public void VisitTerminal(ITerminalNode node) { }\n" +
" public void VisitErrorNode(IErrorNode node) { }\n" +
" public void ExitEveryRule(ParserRuleContext ctx) { }\n" +
"\n" +
" public void EnterEveryRule(ParserRuleContext ctx) {\n" +
" for (int i = 0; i \\< ctx.ChildCount; i++) {\n" +
" IParseTree parent = ctx.GetChild(i).Parent;\n" +
" if (!(parent is IRuleNode) || ((IRuleNode)parent).RuleContext != ctx) {\n" +
" throw new Exception(\"Invalid parse tree shape detected.\");\n" +
" }\n" +
" }\n" +
" }\n" +
"}"
);
ST createParserST = new ST(" <parserName> parser = new <parserName>(tokens);\n");
if ( debug ) {
createParserST =
new ST(
" <parserName> parser = new <parserName>(tokens);\n" +
" parser.AddErrorListener(new DiagnosticErrorListener());\n");
}
outputFileST.add("createParser", createParserST);
outputFileST.add("parserName", parserName);
outputFileST.add("lexerName", lexerName);
outputFileST.add("parserStartRuleName", parserStartRuleName);
writeFile(tmpdir, "Test.cs", outputFileST.render());
}
protected void writeLexerTestFile(String lexerName, boolean showDFA) {
ST outputFileST = new ST(
"using System;\n" +
"using Antlr4.Runtime;\n" +
"\n" +
"public class Test {\n" +
" public static void Main(string[] args) {\n" +
" ICharStream input = new AntlrFileStream(args[0]);\n" +
" <lexerName> lex = new <lexerName>(input);\n" +
" CommonTokenStream tokens = new CommonTokenStream(lex);\n" +
" tokens.Fill();\n" +
" foreach (object t in tokens.GetTokens())\n" +
" Console.WriteLine(t);\n" +
(showDFA?"Console.Write(lex.Interpreter.GetDFA(Lexer.DefaultMode).ToLexerString());\n":"")+
" }\n" +
"}"
);
outputFileST.add("lexerName", lexerName);
writeFile(tmpdir, "Test.cs", outputFileST.render());
}
public void writeRecognizerAndCompile(String parserName, String lexerName,
String parserStartRuleName,
boolean debug) {
if ( parserName==null ) {
writeLexerTestFile(lexerName, debug);
}
else {
writeParserTestFile(parserName,
lexerName,
parserStartRuleName,
debug);
}
addSourceFiles("Test.cs");
}
protected void eraseFiles(final String filesEndingWith) {
File tmpdirF = new File(tmpdir);
String[] files = tmpdirF.list();
for(int i = 0; files!=null && i < files.length; i++) {
if ( files[i].endsWith(filesEndingWith) ) {
new File(tmpdir+"/"+files[i]).delete();
}
}
}
protected void eraseFiles() {
if (tmpdir == null) {
return;
}
File tmpdirF = new File(tmpdir);
String[] files = tmpdirF.list();
if(files!=null) for(String file : files) {
new File(tmpdir+"/"+file).delete();
}
}
protected void eraseTempDir() {
File tmpdirF = new File(tmpdir);
if ( tmpdirF.exists() ) {
eraseFiles();
tmpdirF.delete();
}
}
public String getFirstLineOfException() {
if ( this.stderrDuringParse ==null ) {
return null;
}
String[] lines = this.stderrDuringParse.split("\n");
String prefix="Exception in thread \"main\" ";
return lines[0].substring(prefix.length(),lines[0].length());
}
public List<String> realElements(List<String> elements) {
return elements.subList(Token.MIN_USER_TOKEN_TYPE, elements.size());
}
public void assertNotNullOrEmpty(String message, String text) {
assertNotNull(message, text);
assertFalse(message, text.isEmpty());
}
public void assertNotNullOrEmpty(String text) {
assertNotNull(text);
assertFalse(text.isEmpty());
}
/** Return map sorted by key */
public <K extends Comparable<? super K>,V> LinkedHashMap<K,V> sort(Map<K,V> data) {
LinkedHashMap<K,V> dup = new LinkedHashMap<K, V>();
List<K> keys = new ArrayList<K>();
keys.addAll(data.keySet());
Collections.sort(keys);
for (K k : keys) {
dup.put(k, data.get(k));
}
return dup;
}
protected static void assertEquals(String msg, int a, int b) {
org.junit.Assert.assertEquals(msg, a, b);
}
protected static void assertEquals(String a, String b) {
a = absorbExpectedDifferences(a);
b = absorbActualDifferences(b);
org.junit.Assert.assertEquals(a, b);
}
protected static void assertNull(String a) {
a = absorbActualDifferences(a);
org.junit.Assert.assertNull(a);
}
private static String absorbExpectedDifferences(String a) {
if(a==null)
return a;
// work around the lack of requiresFullContext field in DFAState
if(a.startsWith("Decision"))
a = a.replaceAll("\\^", "");
// work around the algo difference for full context
a = stripOutUnwantedLinesWith(a, "reportAttemptingFullContext","reportContextSensitivity", "reportAmbiguity");
if(a.isEmpty())
a = null;
return a;
}
private static String absorbActualDifferences(String a) {
if(a==null)
return a;
// work around the algo difference for full context
// work around the algo difference for semantic predicates
a = stripOutUnwantedLinesWith(a, "reportContextSensitivity","eval=false");
if(a.isEmpty())
a = null;
return a;
}
private static String stripOutUnwantedLinesWith(String a, String ... unwanteds) {
String[] lines = a.split("\n");
StringBuilder sb = new StringBuilder();
for(String line : lines) {
boolean wanted = true;
for(String unwanted : unwanteds) {
if(line.contains(unwanted) ) {
wanted = false;
break;
}
}
if(!wanted)
continue;
sb.append(line);
sb.append("\n");
}
return sb.toString();
}
}

View File

@ -0,0 +1,395 @@
TestFile(file) ::= <<
package org.antlr.v4.test.runtime.csharp;
import org.antlr.v4.test.runtime.csharp.BaseTest;
import org.junit.Test;
<if(file.Options.("ImportErrorQueue"))>
import org.antlr.v4.test.tool.ErrorQueue;
<endif>
<if(file.Options.("ImportGrammar"))>
import org.antlr.v4.tool.Grammar;
<endif>
import static org.junit.Assert.*;
public class Test<file.name> extends BaseTest {
<file.tests:{test | <test>}; separator="\n", wrap, anchor>
}<\n>
>>
LexerTestMethod(test) ::= <<
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test public void test<test.name>() throws Exception {
mkdir(tmpdir);
<test.SlaveGrammars:{grammar |
String slave_<grammar> =<writeStringLiteral(test.SlaveGrammars.(grammar))>;
writeFile(tmpdir, "<grammar>.g4", slave_<grammar>);
}; separator="\n">
<test.Grammar:{grammar |
<buildStringLiteral(test.Grammar.(grammar), "grammar")>
<test.afterGrammar>
String input =<writeStringLiteral(test.Input)>;
String found = execLexer("<grammar>.g4", grammar, "<grammar><if(test.Options.("CombinedGrammar"))>Lexer<endif>", input, <writeBoolean(test.Options.("ShowDFA"))>);
assertEquals(<writeStringLiteral(test.Output)>, found);
<if(!isEmpty.(test.Errors))>
assertEquals(<writeStringLiteral(test.Errors)>, this.stderrDuringParse);
<else>
assertNull(this.stderrDuringParse);
<endif>
}>
}
>>
CompositeLexerTestMethod(test) ::= <<
<LexerTestMethod(test)>
>>
ParserTestMethod(test) ::= <<
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test public void test<test.name>() throws Exception {
mkdir(tmpdir);
<test.SlaveGrammars:{grammar |
String slave_<grammar> =<writeStringLiteral(test.SlaveGrammars.(grammar))>;
<if(test.Options.("SlaveIsLexer"))>
rawGenerateAndBuildRecognizer("<grammar>.g4", slave_<grammar>, null, "<grammar>");
<else>
writeFile(tmpdir, "<grammar>.g4", slave_<grammar>);
<endif>
}; separator="\n">
<test.Grammar:{grammar |
<buildStringLiteral(test.Grammar.(grammar), "grammar")>
<test.afterGrammar>
String input =<writeStringLiteral(test.Input)>;
String found = execParser("<grammar>.g4", grammar, "<grammar>Parser", "<grammar>Lexer", "<test.Rule>", input, <writeBoolean(test.Options.("Debug"))>);
assertEquals(<writeStringLiteral(test.Output)>, found);
<if(!isEmpty.(test.Errors))>
assertEquals(<writeStringLiteral(test.Errors)>, this.stderrDuringParse);
<else>
assertNull(this.stderrDuringParse);
<endif>
}>
}
>>
CompositeParserTestMethod(test) ::= <<
<ParserTestMethod(test)>
>>
AbstractParserTestMethod(test) ::= <<
/* this file and method are generated, any edit will be overwritten by the next generation */
String test<test.name>(String input) throws Exception {
String grammar = <test.grammar.lines:{ line | "<line>};separator="\\n\" +\n", wrap, anchor>";
return execParser("<test.grammar.grammarName>.g4", grammar, "<test.grammar.grammarName>Parser", "<test.grammar.grammarName>Lexer", "<test.startRule>", input, <test.debug>);
}
>>
ConcreteParserTestMethod(test) ::= <<
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void test<test.name>() throws Exception {
String found = test<test.baseName>("<test.input>");
assertEquals("<test.expectedOutput>", found);
<if(test.expectedErrors)>
assertEquals("<test.expectedErrors>", this.stderrDuringParse);
<else>
assertNull(this.stderrDuringParse);
<endif>
}
>>
string(text) ::= <<
"<escape.(text)>"
>>
writeBoolean(o) ::= "<if(o && !isEmpty.(o))>true<else>false<endif>"
buildStringLiteral(text, variable) ::= <<
StringBuilder <variable>Builder = new StringBuilder(<strlen.(text)>);
<lines.(text):{line|<variable>Builder.append("<escape.(line)>");}; separator="\n">
String <variable> = <variable>Builder.toString();
>>
writeStringLiteral(text) ::= <%
<if(isEmpty.(text))>
""
<else>
<writeLines(lines.(text))>
<endif>
%>
writeLines(textLines) ::= <%
<if(rest(textLines))>
<textLines:{line|
<\n> "<escape.(line)>}; separator="\" +">"
<else>
"<escape.(first(textLines))>"
<endif>
%>
writeln(s) ::= <<Console.WriteLine(<s>);>>
write(s) ::= <<Console.Write(<s>);>>
False() ::= "false"
True() ::= "true"
Not(v) ::= "!<v>"
Assert(s) ::= <<Debug.Assert(<s>);>>
Cast(t,v) ::= "((<t>)<v>)"
Append(a,b) ::= "<a> + <b>"
Concat(a,b) ::= "<a><b>"
DeclareLocal(s,v) ::= "Object <s> = <v>;"
DeclareListLocal(s,v) ::= "List <s> = <v>;"
AssignLocal(s,v) ::= "<s> = <v>;"
InitIntMember(n,v) ::= <%int <n> = <v>;%>
InitBooleanMember(n,v) ::= <%bool <n> = <v>;%>
GetMember(n) ::= <%this.<n>%>
SetMember(n,v) ::= <%this.<n> = <v>;%>
AddMember(n,v) ::= <%this.<n> += <v>;%>
PlusMember(v,n) ::= <%<v> + this.<n>%>
MemberEquals(n,v) ::= <%this.<n> == <v>%>
ModMemberEquals(n,m,v) ::= <%this.<n> % <m> == <v>%>
ModMemberNotEquals(n,m,v) ::= <%this.<n> % <m> != <v>%>
DumpDFA() ::= "this.DumpDFA();"
Pass() ::= ""
StringList() ::= "List\<String>"
BuildParseTrees() ::= "this.BuildParseTree = true;"
BailErrorStrategy() ::= <%ErrorHandler = new BailErrorStrategy();%>
ToStringTree(s) ::= <%<s>.ToStringTree(this)%>
Column() ::= "this.Column"
Text() ::= "this.Text"
ValEquals(a,b) ::= <%<a>==<b>%>
TextEquals(a) ::= <%this.Text.Equals("<a>")%>
PlusText(a) ::= <%"<a>" + this.Text%>
InputText() ::= "this.TokenStream.GetText()"
LTEquals(i, v) ::= <%this.TokenStream.Lt(<i>).Text.Equals(<v>)%>
LANotEquals(i, v) ::= <%this.InputStream.La(<i>)!=<v>%>
TokenStartColumnEquals(i) ::= <%this.TokenStartColumn==<i>%>
ImportListener(X) ::= ""
GetExpectedTokenNames() ::= "this.GetExpectedTokens().ToString(this.Vocabulary)"
RuleInvocationStack() ::= "GetRuleInvocationStackAsString()"
LL_EXACT_AMBIG_DETECTION() ::= <<Interpreter.PredictionMode = PredictionMode.LlExactAmbigDetection;>>
ParserPropertyMember() ::= <<
@members {
bool Property() {
return true;
}
}
>>
PositionAdjustingLexer() ::= <<
public override IToken NextToken() {
if (!(Interpreter is PositionAdjustingLexerATNSimulator)) {
Interpreter = new PositionAdjustingLexerATNSimulator(this, _ATN);
}
return base.NextToken();
}
public override IToken Emit() {
switch (Type) {
case TOKENS:
HandleAcceptPositionForKeyword("tokens");
break;
case LABEL:
HandleAcceptPositionForIdentifier();
break;
default:
break;
}
return base.Emit();
}
private bool HandleAcceptPositionForIdentifier() {
string tokenText = this.Text;
int identifierLength = 0;
while (identifierLength \< tokenText.Length && IsIdentifierChar(tokenText[identifierLength])) {
identifierLength++;
}
if (InputStream.Index > TokenStartCharIndex + identifierLength) {
int offset = identifierLength - 1;
getInterpreter().ResetAcceptPosition((ICharStream)InputStream, TokenStartCharIndex + offset, TokenStartLine, TokenStartColumn + offset);
return true;
}
return false;
}
private bool HandleAcceptPositionForKeyword(string keyword) {
if (InputStream.Index > TokenStartCharIndex + keyword.Length) {
int offset = keyword.Length - 1;
getInterpreter().ResetAcceptPosition((ICharStream)InputStream, TokenStartCharIndex + offset, TokenStartLine, TokenStartColumn + offset);
return true;
}
return false;
}
public PositionAdjustingLexerATNSimulator getInterpreter() {
return (PositionAdjustingLexerATNSimulator)base.Interpreter;
}
private static bool IsIdentifierChar(char c) {
return Char.IsLetterOrDigit(c) || c == '_';
}
public class PositionAdjustingLexerATNSimulator : LexerATNSimulator {
public PositionAdjustingLexerATNSimulator(Lexer recog, ATN atn)
: base(recog, atn)
{
}
public void ResetAcceptPosition(ICharStream input, int index, int line, int column) {
input.Seek(index);
this.Line = line;
this.Column = column;
Consume(input);
}
}
>>
BasicListener(X) ::= <<
public class LeafListener : TBaseListener {
public override void VisitTerminal(ITerminalNode node) {
Console.WriteLine(node.Symbol.Text);
}
}
>>
WalkListener(s) ::= <<
ParseTreeWalker walker = new ParseTreeWalker();
walker.Walk(new LeafListener(), <s>);
>>
TokenGetterListener(X) ::= <<
public class LeafListener : TBaseListener {
public override void ExitA(TParser.AContext ctx) {
if (ctx.ChildCount==2)
{
StringBuilder sb = new StringBuilder ("[");
foreach (ITerminalNode node in ctx.INT ()) {
sb.Append (node.ToString ());
sb.Append (", ");
}
sb.Length = sb.Length - 2;
sb.Append ("]");
Console.Write ("{0} {1} {2}", ctx.INT (0).Symbol.Text,
ctx.INT (1).Symbol.Text, sb.ToString());
}
else
Console.WriteLine(ctx.ID().Symbol);
}
}
>>
RuleGetterListener(X) ::= <<
public class LeafListener : TBaseListener {
public override void ExitA(TParser.AContext ctx) {
if (ctx.ChildCount==2) {
Console.Write("{0} {1} {2}",ctx.b(0).Start.Text,
ctx.b(1).Start.Text,ctx.b()[0].Start.Text);
} else
Console.WriteLine(ctx.b(0).Start.Text);
}
}
>>
LRListener(X) ::= <<
public class LeafListener : TBaseListener {
public override void ExitE(TParser.EContext ctx) {
if (ctx.ChildCount==3) {
Console.Write("{0} {1} {2}\n",ctx.e(0).Start.Text,
ctx.e(1).Start.Text, ctx.e()[0].Start.Text);
} else
Console.WriteLine(ctx.INT().Symbol.Text);
}
}
>>
LRWithLabelsListener(X) ::= <<
public class LeafListener : TBaseListener {
public override void ExitCall(TParser.CallContext ctx) {
Console.Write("{0} {1}",ctx.e().Start.Text,ctx.eList());
}
public override void ExitInt(TParser.IntContext ctx) {
Console.WriteLine(ctx.INT().Symbol.Text);
}
}
>>
DeclareContextListGettersFunction() ::= <<
void foo() {
SContext s = null;
AContext[] a = s.a();
BContext[] b = s.b();
}
>>
Declare_foo() ::= <<public void foo() {Console.WriteLine("foo");}>>
Invoke_foo() ::= "this.foo();"
Declare_pred() ::= <<bool pred(bool v) {
Console.WriteLine("eval="+v.ToString().ToLower());
return v;
}
>>
Invoke_pred(v) ::= <<this.pred(<v>)>>
isEmpty ::= [
"": true,
default: false
]