forked from jasder/antlr
added more unit tests
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9086]
This commit is contained in:
parent
82360bfaa8
commit
9e69640bc1
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 Terence Parr
|
||||
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.runtime.tree;
|
||||
|
||||
import org.antlr.runtime.misc.IntArray;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/** A buffered stream of tree nodes. Nodes can be from a tree of ANY kind.
|
||||
*
|
||||
* This node stream sucks all nodes out of the tree specified in
|
||||
* the constructor during construction and makes pointers into
|
||||
* the tree using an array of Object pointers. The stream necessarily
|
||||
* includes pointers to DOWN and UP and EOF nodes.
|
||||
*
|
||||
* This stream knows how to mark/release for backtracking.
|
||||
*
|
||||
* This stream is most suitable for tree interpreters that need to
|
||||
* jump around a lot or for tree parsers requiring speed (at cost of memory).
|
||||
* There is some duplicated functionality here with UnBufferedASTNodeStream
|
||||
* but just in bookkeeping, not tree walking etc...
|
||||
*
|
||||
* TARGET DEVELOPERS:
|
||||
*
|
||||
* This is the old CommonASTNodeStream that buffered up entire node stream.
|
||||
* No need to implement really as new CommonASTNodeStream is much better
|
||||
* and covers what we need.
|
||||
*
|
||||
* @see CommonASTNodeStream
|
||||
*/
|
||||
public class BufferedASTNodeStream implements ASTNodeStream {
|
||||
public static final int DEFAULT_INITIAL_BUFFER_SIZE = 100;
|
||||
public static final int INITIAL_CALL_STACK_SIZE = 10;
|
||||
|
||||
protected class StreamIterator implements Iterator {
|
||||
int i = 0;
|
||||
public boolean hasNext() {
|
||||
return i<nodes.size();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
int current = i;
|
||||
i++;
|
||||
if ( current < nodes.size() ) {
|
||||
return nodes.get(current);
|
||||
}
|
||||
return eof;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new RuntimeException("cannot remove nodes from stream");
|
||||
}
|
||||
}
|
||||
|
||||
// all these navigation nodes are shared and hence they
|
||||
// cannot contain any line/column info
|
||||
|
||||
protected Object down;
|
||||
protected Object up;
|
||||
protected Object eof;
|
||||
|
||||
/** The complete mapping from stream index to tree node.
|
||||
* This buffer includes pointers to DOWN, UP, and EOF nodes.
|
||||
* It is built upon ctor invocation. The elements are type
|
||||
* Object as we don't what the trees look like.
|
||||
*
|
||||
* Load upon first need of the buffer so we can set token types
|
||||
* of interest for reverseIndexing. Slows us down a wee bit to
|
||||
* do all of the if p==-1 testing everywhere though.
|
||||
*/
|
||||
protected List nodes;
|
||||
|
||||
/** Pull nodes from which tree? */
|
||||
protected Object root;
|
||||
|
||||
/** IF this tree (root) was created from a token stream, track it. */
|
||||
protected TokenStream tokens;
|
||||
|
||||
/** What tree adaptor was used to build these trees */
|
||||
ASTAdaptor adaptor;
|
||||
|
||||
/** Reuse same DOWN, UP navigation nodes unless this is true */
|
||||
protected boolean uniqueNavigationNodes = false;
|
||||
|
||||
/** The index into the nodes list of the current node (next node
|
||||
* to consume). If -1, nodes array not filled yet.
|
||||
*/
|
||||
protected int p = -1;
|
||||
|
||||
/** Track the last mark() call result value for use in rewind(). */
|
||||
protected int lastMarker;
|
||||
|
||||
/** Stack of indexes used for push/pop calls */
|
||||
protected IntArray calls;
|
||||
|
||||
public BufferedASTNodeStream(Object tree) {
|
||||
this(new CommonASTAdaptor(), tree);
|
||||
}
|
||||
|
||||
public BufferedASTNodeStream(ASTAdaptor adaptor, Object tree) {
|
||||
this(adaptor, tree, DEFAULT_INITIAL_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
public BufferedASTNodeStream(ASTAdaptor adaptor, Object tree, int initialBufferSize) {
|
||||
this.root = tree;
|
||||
this.adaptor = adaptor;
|
||||
nodes = new ArrayList(initialBufferSize);
|
||||
down = adaptor.create(Token.DOWN, "DOWN");
|
||||
up = adaptor.create(Token.UP, "UP");
|
||||
eof = adaptor.create(Token.EOF, "EOF");
|
||||
}
|
||||
|
||||
/** Walk tree with depth-first-search and fill nodes buffer.
|
||||
* Don't do DOWN, UP nodes if its a list (t is isNil).
|
||||
*/
|
||||
protected void fillBuffer() {
|
||||
fillBuffer(root);
|
||||
//System.out.println("revIndex="+tokenTypeToStreamIndexesMap);
|
||||
p = 0; // buffer of nodes intialized now
|
||||
}
|
||||
|
||||
public void fillBuffer(Object t) {
|
||||
boolean nil = adaptor.isNil(t);
|
||||
if ( !nil ) {
|
||||
nodes.add(t); // add this node
|
||||
}
|
||||
// add DOWN node if t has children
|
||||
int n = adaptor.getChildCount(t);
|
||||
if ( !nil && n>0 ) {
|
||||
addNavigationNode(Token.DOWN);
|
||||
}
|
||||
// and now add all its children
|
||||
for (int c=0; c<n; c++) {
|
||||
Object child = adaptor.getChild(t,c);
|
||||
fillBuffer(child);
|
||||
}
|
||||
// add UP node if t has children
|
||||
if ( !nil && n>0 ) {
|
||||
addNavigationNode(Token.UP);
|
||||
}
|
||||
}
|
||||
|
||||
/** What is the stream index for node? 0..n-1
|
||||
* Return -1 if node not found.
|
||||
*/
|
||||
protected int getNodeIndex(Object node) {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
Object t = (Object) nodes.get(i);
|
||||
if ( t==node ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** As we flatten the tree, we use UP, DOWN nodes to represent
|
||||
* the tree structure. When debugging we need unique nodes
|
||||
* so instantiate new ones when uniqueNavigationNodes is true.
|
||||
*/
|
||||
protected void addNavigationNode(final int ttype) {
|
||||
Object navNode = null;
|
||||
if ( ttype==Token.DOWN ) {
|
||||
if ( hasUniqueNavigationNodes() ) {
|
||||
navNode = adaptor.create(Token.DOWN, "DOWN");
|
||||
}
|
||||
else {
|
||||
navNode = down;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( hasUniqueNavigationNodes() ) {
|
||||
navNode = adaptor.create(Token.UP, "UP");
|
||||
}
|
||||
else {
|
||||
navNode = up;
|
||||
}
|
||||
}
|
||||
nodes.add(navNode);
|
||||
}
|
||||
|
||||
public Object get(int i) {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
return nodes.get(i);
|
||||
}
|
||||
|
||||
public Object LT(int k) {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
if ( k==0 ) {
|
||||
return null;
|
||||
}
|
||||
if ( k<0 ) {
|
||||
return LB(-k);
|
||||
}
|
||||
//System.out.print("LT(p="+p+","+k+")=");
|
||||
if ( (p+k-1) >= nodes.size() ) {
|
||||
return eof;
|
||||
}
|
||||
return nodes.get(p+k-1);
|
||||
}
|
||||
|
||||
public Object getCurrentSymbol() { return LT(1); }
|
||||
|
||||
/*
|
||||
public Object getLastTreeNode() {
|
||||
int i = index();
|
||||
if ( i>=size() ) {
|
||||
i--; // if at EOF, have to start one back
|
||||
}
|
||||
System.out.println("start last node: "+i+" size=="+nodes.size());
|
||||
while ( i>=0 &&
|
||||
(adaptor.getType(get(i))==Token.EOF ||
|
||||
adaptor.getType(get(i))==Token.UP ||
|
||||
adaptor.getType(get(i))==Token.DOWN) )
|
||||
{
|
||||
i--;
|
||||
}
|
||||
System.out.println("stop at node: "+i+" "+nodes.get(i));
|
||||
return nodes.get(i);
|
||||
}
|
||||
*/
|
||||
|
||||
/** Look backwards k nodes */
|
||||
protected Object LB(int k) {
|
||||
if ( k==0 ) {
|
||||
return null;
|
||||
}
|
||||
if ( (p-k)<0 ) {
|
||||
return null;
|
||||
}
|
||||
return nodes.get(p-k);
|
||||
}
|
||||
|
||||
public Object getTreeSource() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public String getSourceName() {
|
||||
return getTokenStream().getSourceName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASTAdaptor getTreeAdaptor() {
|
||||
return adaptor;
|
||||
}
|
||||
|
||||
public TokenStream getTokenStream() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public void setTokenStream(TokenStream tokens) {
|
||||
this.tokens = tokens;
|
||||
}
|
||||
|
||||
public ASTAdaptor getASTAdaptor() {
|
||||
return adaptor;
|
||||
}
|
||||
|
||||
public void setASTAdaptor(ASTAdaptor adaptor) {
|
||||
this.adaptor = adaptor;
|
||||
}
|
||||
|
||||
public boolean hasUniqueNavigationNodes() {
|
||||
return uniqueNavigationNodes;
|
||||
}
|
||||
|
||||
public void setUniqueNavigationNodes(boolean uniqueNavigationNodes) {
|
||||
this.uniqueNavigationNodes = uniqueNavigationNodes;
|
||||
}
|
||||
|
||||
public void consume() {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
public int LA(int i) {
|
||||
return adaptor.getType(LT(i));
|
||||
}
|
||||
|
||||
public int mark() {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
lastMarker = index();
|
||||
return lastMarker;
|
||||
}
|
||||
|
||||
public void release(int marker) {
|
||||
// no resources to release
|
||||
}
|
||||
|
||||
public int index() {
|
||||
return p;
|
||||
}
|
||||
|
||||
public void rewind(int marker) {
|
||||
seek(marker);
|
||||
}
|
||||
|
||||
public void rewind() {
|
||||
seek(lastMarker);
|
||||
}
|
||||
|
||||
public void seek(int index) {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
p = index;
|
||||
}
|
||||
|
||||
/** Make stream jump to a new location, saving old location.
|
||||
* Switch back with pop().
|
||||
*/
|
||||
public void push(int index) {
|
||||
if ( calls==null ) {
|
||||
calls = new IntArray();
|
||||
}
|
||||
calls.push(p); // save current index
|
||||
seek(index);
|
||||
}
|
||||
|
||||
/** Seek back to previous index saved during last push() call.
|
||||
* Return top of stack (return index).
|
||||
*/
|
||||
public int pop() {
|
||||
int ret = calls.pop();
|
||||
seek(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
p = 0;
|
||||
lastMarker = 0;
|
||||
if (calls != null) {
|
||||
calls.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
return nodes.size();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
return new StreamIterator();
|
||||
}
|
||||
|
||||
// TREE REWRITE INTERFACE
|
||||
|
||||
public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
|
||||
if ( parent!=null ) {
|
||||
adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
|
||||
}
|
||||
}
|
||||
|
||||
/** Used for testing, just return the token type stream */
|
||||
public String toTokenTypeString() {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
Object t = (Object) nodes.get(i);
|
||||
buf.append(" ");
|
||||
buf.append(adaptor.getType(t));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/** Debugging */
|
||||
public String toTokenString(int start, int stop) {
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = start; i < nodes.size() && i <= stop; i++) {
|
||||
Object t = (Object) nodes.get(i);
|
||||
buf.append(" ");
|
||||
buf.append(adaptor.getToken(t));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String toString(Object start, Object stop) {
|
||||
System.out.println("toString");
|
||||
if ( start==null || stop==null ) {
|
||||
return null;
|
||||
}
|
||||
if ( p==-1 ) {
|
||||
fillBuffer();
|
||||
}
|
||||
//System.out.println("stop: "+stop);
|
||||
if ( start instanceof CommonAST )
|
||||
System.out.print("toString: "+((CommonAST)start).getToken()+", ");
|
||||
else
|
||||
System.out.println(start);
|
||||
if ( stop instanceof CommonAST )
|
||||
System.out.println(((CommonAST)stop).getToken());
|
||||
else
|
||||
System.out.println(stop);
|
||||
// if we have the token stream, use that to dump text in order
|
||||
if ( tokens!=null ) {
|
||||
int beginTokenIndex = adaptor.getTokenStartIndex(start);
|
||||
int endTokenIndex = adaptor.getTokenStopIndex(stop);
|
||||
// if it's a tree, use start/stop index from start node
|
||||
// else use token range from start/stop nodes
|
||||
if ( adaptor.getType(stop)==Token.UP ) {
|
||||
endTokenIndex = adaptor.getTokenStopIndex(start);
|
||||
}
|
||||
else if ( adaptor.getType(stop)==Token.EOF ) {
|
||||
endTokenIndex = size()-2; // don't use EOF
|
||||
}
|
||||
return tokens.toString(beginTokenIndex, endTokenIndex);
|
||||
}
|
||||
// walk nodes looking for start
|
||||
Object t = null;
|
||||
int i = 0;
|
||||
for (; i < nodes.size(); i++) {
|
||||
t = nodes.get(i);
|
||||
if ( t==start ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now walk until we see stop, filling string buffer with text
|
||||
StringBuffer buf = new StringBuffer();
|
||||
t = nodes.get(i);
|
||||
while ( t!=stop ) {
|
||||
String text = adaptor.getText(t);
|
||||
if ( text==null ) {
|
||||
text = " "+String.valueOf(adaptor.getType(t));
|
||||
}
|
||||
buf.append(text);
|
||||
i++;
|
||||
t = nodes.get(i);
|
||||
}
|
||||
// include stop node too
|
||||
String text = adaptor.getText(stop);
|
||||
if ( text==null ) {
|
||||
text = " "+String.valueOf(adaptor.getType(stop));
|
||||
}
|
||||
buf.append(text);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
|
@ -30,17 +30,27 @@ package org.antlr.v4.test;
|
|||
|
||||
import org.antlr.v4.Tool;
|
||||
import org.antlr.v4.automata.*;
|
||||
import org.antlr.v4.codegen.CodeGenerator;
|
||||
import org.antlr.v4.misc.Utils;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
import org.antlr.v4.runtime.atn.ATN;
|
||||
import org.antlr.v4.runtime.atn.ATNState;
|
||||
import org.antlr.v4.runtime.atn.DecisionState;
|
||||
import org.antlr.v4.runtime.atn.LexerATNSimulator;
|
||||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.semantics.SemanticPipeline;
|
||||
import org.antlr.v4.tool.*;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
import org.junit.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.stringtemplate.v4.ST;
|
||||
import org.stringtemplate.v4.STGroup;
|
||||
import org.stringtemplate.v4.STGroupString;
|
||||
|
||||
import javax.tools.*;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.ToolProvider;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -662,7 +672,7 @@ public abstract class BaseTest {
|
|||
msg = msg.replaceAll("\t","\\\\t");
|
||||
|
||||
// ignore error number
|
||||
expect = stripErrorNum(expect);
|
||||
if ( expect!=null ) expect = stripErrorNum(expect);
|
||||
actual = stripErrorNum(actual);
|
||||
assertEquals("error in: "+msg,expect,actual);
|
||||
}
|
||||
|
@ -756,6 +766,44 @@ public abstract class BaseTest {
|
|||
assertEquals(expecting, result);
|
||||
}
|
||||
|
||||
public void testActions(String templates, String actionName, String action, String expected) {
|
||||
int lp = templates.indexOf('(');
|
||||
String name = templates.substring(0, lp);
|
||||
STGroup group = new STGroupString(templates);
|
||||
ST st = group.getInstanceOf(name);
|
||||
st.add(actionName, action);
|
||||
String grammar = st.render();
|
||||
try {
|
||||
ErrorQueue equeue = new ErrorQueue();
|
||||
Grammar g = new Grammar(grammar);
|
||||
if ( g.ast!=null && !g.ast.hasErrors ) {
|
||||
SemanticPipeline sem = new SemanticPipeline(g);
|
||||
sem.process();
|
||||
|
||||
ATNFactory factory = new ParserATNFactory(g);
|
||||
if ( g.isLexer() ) factory = new LexerATNFactory((LexerGrammar)g);
|
||||
g.atn = factory.createATN();
|
||||
|
||||
CodeGenerator gen = new CodeGenerator(g);
|
||||
ST outputFileST = gen.generateParser();
|
||||
String output = outputFileST.render();
|
||||
//System.out.println(output);
|
||||
String b = "#" + actionName + "#";
|
||||
int start = output.indexOf(b);
|
||||
String e = "#end-" + actionName + "#";
|
||||
int end = output.indexOf(e);
|
||||
String snippet = output.substring(start+b.length(),end);
|
||||
assertEquals(expected, snippet);
|
||||
}
|
||||
if ( equeue.size()>0 ) {
|
||||
System.err.println(equeue.toString(g.tool));
|
||||
}
|
||||
}
|
||||
catch (org.antlr.runtime.RecognitionException re) {
|
||||
re.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StreamVacuum implements Runnable {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
BufferedReader in;
|
||||
|
|
|
@ -27,12 +27,13 @@
|
|||
*/
|
||||
package org.antlr.v4.test;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.CommonToken;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Test the tree node stream. */
|
||||
public class TestTreeNodeStream extends BaseTest {
|
||||
public class TestASTNodeStream extends BaseTest {
|
||||
public static final String DN = " "+Token.DOWN+" ";
|
||||
public static final String UP = " "+Token.UP;
|
||||
|
|
@ -1,12 +1,6 @@
|
|||
package org.antlr.v4.test;
|
||||
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.antlr.v4.automata.*;
|
||||
import org.antlr.v4.codegen.CodeGenerator;
|
||||
import org.antlr.v4.semantics.SemanticPipeline;
|
||||
import org.antlr.v4.tool.*;
|
||||
import org.junit.Test;
|
||||
import org.stringtemplate.v4.*;
|
||||
|
||||
/** */
|
||||
public class TestActionTranslation extends BaseTest {
|
||||
|
@ -407,43 +401,4 @@ public class TestActionTranslation extends BaseTest {
|
|||
}
|
||||
|
||||
// TODO: nonlocal $rule::x
|
||||
|
||||
|
||||
public void testActions(String templates, String actionName, String action, String expected) {
|
||||
int lp = templates.indexOf('(');
|
||||
String name = templates.substring(0, lp);
|
||||
STGroup group = new STGroupString(templates);
|
||||
ST st = group.getInstanceOf(name);
|
||||
st.add(actionName, action);
|
||||
String grammar = st.render();
|
||||
try {
|
||||
ErrorQueue equeue = new ErrorQueue();
|
||||
Grammar g = new Grammar(grammar);
|
||||
if ( g.ast!=null && !g.ast.hasErrors ) {
|
||||
SemanticPipeline sem = new SemanticPipeline(g);
|
||||
sem.process();
|
||||
|
||||
ATNFactory factory = new ParserATNFactory(g);
|
||||
if ( g.isLexer() ) factory = new LexerATNFactory((LexerGrammar)g);
|
||||
g.atn = factory.createATN();
|
||||
|
||||
CodeGenerator gen = new CodeGenerator(g);
|
||||
ST outputFileST = gen.generateParser();
|
||||
String output = outputFileST.render();
|
||||
//System.out.println(output);
|
||||
String b = "#" + actionName + "#";
|
||||
int start = output.indexOf(b);
|
||||
String e = "#end-" + actionName + "#";
|
||||
int end = output.indexOf(e);
|
||||
String snippet = output.substring(start+b.length(),end);
|
||||
assertEquals(expected, snippet);
|
||||
}
|
||||
if ( equeue.size()>0 ) {
|
||||
System.err.println(equeue.toString(g.tool));
|
||||
}
|
||||
}
|
||||
catch (RecognitionException re) {
|
||||
re.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2010 Terence Parr
|
||||
* 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;
|
||||
|
||||
import org.antlr.v4.runtime.CommonToken;
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestBufferedASTNodeStream extends TestASTNodeStream {
|
||||
// inherits tests; these methods make it use a new buffer
|
||||
|
||||
public ASTNodeStream newStream(Object t) {
|
||||
return new BufferedASTNodeStream(t);
|
||||
}
|
||||
|
||||
public String toTokenTypeString(ASTNodeStream stream) {
|
||||
return ((BufferedASTNodeStream)stream).toTokenTypeString();
|
||||
}
|
||||
|
||||
@Test public void testSeek() throws Exception {
|
||||
// ^(101 ^(102 103 ^(106 107) ) 104 105)
|
||||
// stream has 7 real + 6 nav nodes
|
||||
// Sequence of types: 101 DN 102 DN 103 106 DN 107 UP UP 104 105 UP EOF
|
||||
BaseAST r0 = new CommonAST(new CommonToken(101));
|
||||
BaseAST r1 = new CommonAST(new CommonToken(102));
|
||||
r0.addChild(r1);
|
||||
r1.addChild(new CommonAST(new CommonToken(103)));
|
||||
BaseAST r2 = new CommonAST(new CommonToken(106));
|
||||
r2.addChild(new CommonAST(new CommonToken(107)));
|
||||
r1.addChild(r2);
|
||||
r0.addChild(new CommonAST(new CommonToken(104)));
|
||||
r0.addChild(new CommonAST(new CommonToken(105)));
|
||||
|
||||
ASTNodeStream stream = newStream(r0);
|
||||
stream.consume(); // consume 101
|
||||
stream.consume(); // consume DN
|
||||
stream.consume(); // consume 102
|
||||
stream.seek(7); // seek to 107
|
||||
assertEquals(107, ((AST)stream.LT(1)).getType());
|
||||
stream.consume(); // consume 107
|
||||
stream.consume(); // consume UP
|
||||
stream.consume(); // consume UP
|
||||
assertEquals(104, ((AST)stream.LT(1)).getType());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2010 Terence Parr
|
||||
* 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;
|
||||
|
||||
import org.antlr.runtime.misc.FastQueue;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TestFastQueue {
|
||||
@Test public void testQueueNoRemove() throws Exception {
|
||||
FastQueue<String> q = new FastQueue<String>();
|
||||
q.add("a");
|
||||
q.add("b");
|
||||
q.add("c");
|
||||
q.add("d");
|
||||
q.add("e");
|
||||
String expecting = "a b c d e";
|
||||
String found = q.toString();
|
||||
assertEquals(expecting, found);
|
||||
}
|
||||
|
||||
@Test public void testQueueThenRemoveAll() throws Exception {
|
||||
FastQueue<String> q = new FastQueue<String>();
|
||||
q.add("a");
|
||||
q.add("b");
|
||||
q.add("c");
|
||||
q.add("d");
|
||||
q.add("e");
|
||||
StringBuffer buf = new StringBuffer();
|
||||
while ( q.size()>0 ) {
|
||||
String o = q.remove();
|
||||
buf.append(o);
|
||||
if ( q.size()>0 ) buf.append(" ");
|
||||
}
|
||||
assertEquals("queue should be empty", 0, q.size());
|
||||
String expecting = "a b c d e";
|
||||
String found = buf.toString();
|
||||
assertEquals(expecting, found);
|
||||
}
|
||||
|
||||
@Test public void testQueueThenRemoveOneByOne() throws Exception {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
FastQueue<String> q = new FastQueue<String>();
|
||||
q.add("a");
|
||||
buf.append(q.remove());
|
||||
q.add("b");
|
||||
buf.append(q.remove());
|
||||
q.add("c");
|
||||
buf.append(q.remove());
|
||||
q.add("d");
|
||||
buf.append(q.remove());
|
||||
q.add("e");
|
||||
buf.append(q.remove());
|
||||
assertEquals("queue should be empty", 0, q.size());
|
||||
String expecting = "abcde";
|
||||
String found = buf.toString();
|
||||
assertEquals(expecting, found);
|
||||
}
|
||||
|
||||
// E r r o r s
|
||||
|
||||
@Test public void testGetFromEmptyQueue() throws Exception {
|
||||
FastQueue<String> q = new FastQueue<String>();
|
||||
String msg = null;
|
||||
try { q.remove(); }
|
||||
catch (NoSuchElementException nsee) {
|
||||
msg = nsee.getMessage();
|
||||
}
|
||||
String expecting = "queue index 0 > last index -1";
|
||||
String found = msg;
|
||||
assertEquals(expecting, found);
|
||||
}
|
||||
|
||||
@Test public void testGetFromEmptyQueueAfterSomeAdds() throws Exception {
|
||||
FastQueue<String> q = new FastQueue<String>();
|
||||
q.add("a");
|
||||
q.add("b");
|
||||
q.remove();
|
||||
q.remove();
|
||||
String msg = null;
|
||||
try { q.remove(); }
|
||||
catch (NoSuchElementException nsee) {
|
||||
msg = nsee.getMessage();
|
||||
}
|
||||
String expecting = "queue index 0 > last index -1";
|
||||
String found = msg;
|
||||
assertEquals(expecting, found);
|
||||
}
|
||||
|
||||
@Test public void testGetFromEmptyQueueAfterClear() throws Exception {
|
||||
FastQueue<String> q = new FastQueue<String>();
|
||||
q.add("a");
|
||||
q.add("b");
|
||||
q.clear();
|
||||
String msg = null;
|
||||
try { q.remove(); }
|
||||
catch (NoSuchElementException nsee) {
|
||||
msg = nsee.getMessage();
|
||||
}
|
||||
String expecting = "queue index 0 > last index -1";
|
||||
String found = msg;
|
||||
assertEquals(expecting, found);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,544 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2010 Terence Parr
|
||||
* 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;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/** Test hetero trees in parsers and tree parsers */
|
||||
public class TestHeteroAST extends BaseTest {
|
||||
protected boolean debug = false;
|
||||
|
||||
// PARSERS -- AUTO AST
|
||||
|
||||
@Test public void testToken() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID<V> ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTokenCommonAST() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID<CommonAST> ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTokenWithQualifiedType() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID<TParser.V> ;\n"+ // TParser.V is qualified name
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNamedType() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID<node=V> ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a<V>\n", found);
|
||||
}
|
||||
|
||||
|
||||
@Test public void testTokenWithLabel() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : x=ID<V> ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTokenWithListLabel() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : x+=ID<V> ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTokenRoot() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID<V>^ ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTokenRootWithListLabel() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : x+=ID<V>^ ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testString() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : 'begin'<V> ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "begin", debug);
|
||||
assertEquals("begin<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testStringRoot() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : 'begin'<V>^ ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "begin", debug);
|
||||
assertEquals("begin<V>\n", found);
|
||||
}
|
||||
|
||||
// PARSERS -- REWRITE AST
|
||||
|
||||
@Test public void testRewriteToken() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID -> ID<V> ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("a<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testRewriteTokenWithArgs() throws Exception {
|
||||
// arg to ID<V>[42,19,30] means you're constructing node not associated with ID
|
||||
// so must pass in token manually
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {\n" +
|
||||
"static class V extends CommonAST {\n" +
|
||||
" public int x,y,z;\n"+
|
||||
" public V(int ttype, int x, int y, int z) { this.x=x; this.y=y; this.z=z; token=new CommonToken(ttype,\"\"); }\n" +
|
||||
" public V(int ttype, Token t, int x) { token=t; this.x=x;}\n" +
|
||||
" public String toString() { return (token!=null?token.getText():\"\")+\"<V>;\"+x+y+z;}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID -> ID<V>[42,19,30] ID<V>[$ID,99] ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a", debug);
|
||||
assertEquals("<V>;421930 a<V>;9900\n", found);
|
||||
}
|
||||
|
||||
@Test public void testRewriteTokenRoot() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID INT -> ^(ID<V> INT) ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a 2", debug);
|
||||
assertEquals("(a<V> 2)\n", found);
|
||||
}
|
||||
|
||||
@Test public void testRewriteString() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : 'begin' -> 'begin'<V> ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "begin", debug);
|
||||
assertEquals("begin<V>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testRewriteStringRoot() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : 'begin' INT -> ^('begin'<V> INT) ;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "begin 2", debug);
|
||||
assertEquals("(begin<V> 2)\n", found);
|
||||
}
|
||||
|
||||
@Test public void testRewriteRuleResults() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"tokens {LIST;}\n" +
|
||||
"@members {\n" +
|
||||
"static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"static class W extends CommonAST {\n" +
|
||||
" public W(int tokenType, String txt) { super(new CommonToken(tokenType,txt)); }\n" +
|
||||
" public W(Token t) { token=t;}\n" +
|
||||
" public String toString() { return token.getText()+\"<W>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : id (',' id)* -> ^(LIST<W>[\"LIST\"] id+);\n" +
|
||||
"id : ID -> ID<V>;\n"+
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "a,b,c", debug);
|
||||
assertEquals("(LIST<W> a<V> b<V> c<V>)\n", found);
|
||||
}
|
||||
|
||||
@Test public void testCopySemanticsWithHetero() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"@members {\n" +
|
||||
"static class V extends CommonAST {\n" +
|
||||
" public V(Token t) { token=t;}\n" + // for 'int'<V>
|
||||
" public V(V node) { super(node); }\n\n" + // for dupNode
|
||||
" public Tree dupNode() { return new V(this); }\n" + // for dup'ing type
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n" +
|
||||
"a : type ID (',' ID)* ';' -> ^(type ID)+;\n" +
|
||||
"type : 'int'<V> ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "int a, b, c;", debug);
|
||||
assertEquals("(int<V> a) (int<V> b) (int<V> c)\n", found);
|
||||
}
|
||||
|
||||
// TREE PARSERS -- REWRITE AST
|
||||
|
||||
@Test public void testTreeParserRewriteFlatList() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID INT;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {output=AST; ASTLabelType=CommonAST; tokenVocab=T;}\n" +
|
||||
"@members {\n" +
|
||||
"static class V extends CommonAST {\n" +
|
||||
" public V(Object t) { super((CommonAST)t); }\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"static class W extends CommonAST {\n" +
|
||||
" public W(Object t) { super((CommonAST)t); }\n" +
|
||||
" public String toString() { return token.getText()+\"<W>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID INT -> INT<V> ID<W>\n" +
|
||||
" ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "a", "abc 34");
|
||||
assertEquals("34<V> abc<W>\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTreeParserRewriteTree() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID INT;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {output=AST; ASTLabelType=CommonAST; tokenVocab=T;}\n" +
|
||||
"@members {\n" +
|
||||
"static class V extends CommonAST {\n" +
|
||||
" public V(Object t) { super((CommonAST)t); }\n" +
|
||||
" public String toString() { return token.getText()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"static class W extends CommonAST {\n" +
|
||||
" public W(Object t) { super((CommonAST)t); }\n" +
|
||||
" public String toString() { return token.getText()+\"<W>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID INT -> ^(INT<V> ID<W>)\n" +
|
||||
" ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "a", "abc 34");
|
||||
assertEquals("(34<V> abc<W>)\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTreeParserRewriteImaginary() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {output=AST; ASTLabelType=CommonAST; tokenVocab=T;}\n" +
|
||||
"tokens { ROOT; }\n" +
|
||||
"@members {\n" +
|
||||
"class V extends CommonAST {\n" +
|
||||
" public V(int tokenType) { super(new CommonToken(tokenType)); }\n" +
|
||||
" public String toString() { return tokenNames[token.getType()]+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID -> ROOT<V> ID\n" +
|
||||
" ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "a", "abc");
|
||||
assertEquals("ROOT<V> abc\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTreeParserRewriteImaginaryWithArgs() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {output=AST; ASTLabelType=CommonAST; tokenVocab=T;}\n" +
|
||||
"tokens { ROOT; }\n" +
|
||||
"@members {\n" +
|
||||
"class V extends CommonAST {\n" +
|
||||
" public int x;\n" +
|
||||
" public V(int tokenType, int x) { super(new CommonToken(tokenType)); this.x=x;}\n" +
|
||||
" public String toString() { return tokenNames[token.getType()]+\"<V>;\"+x;}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID -> ROOT<V>[42] ID\n" +
|
||||
" ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "a", "abc");
|
||||
assertEquals("ROOT<V>;42 abc\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTreeParserRewriteImaginaryRoot() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {output=AST; ASTLabelType=CommonAST; tokenVocab=T;}\n" +
|
||||
"tokens { ROOT; }\n" +
|
||||
"@members {\n" +
|
||||
"class V extends CommonAST {\n" +
|
||||
" public V(int tokenType) { super(new CommonToken(tokenType)); }\n" +
|
||||
" public String toString() { return tokenNames[token.getType()]+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID -> ^(ROOT<V> ID)\n" +
|
||||
" ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "a", "abc");
|
||||
assertEquals("(ROOT<V> abc)\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTreeParserRewriteImaginaryFromReal() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {output=AST; ASTLabelType=CommonAST; tokenVocab=T;}\n" +
|
||||
"tokens { ROOT; }\n" +
|
||||
"@members {\n" +
|
||||
"class V extends CommonAST {\n" +
|
||||
" public V(int tokenType) { super(new CommonToken(tokenType)); }\n" +
|
||||
" public V(int tokenType, Object tree) { super((CommonAST)tree); token.setType(tokenType); }\n" +
|
||||
" public String toString() { return tokenNames[token.getType()]+\"<V>@\"+token.getLine();}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID -> ROOT<V>[$ID]\n" +
|
||||
" ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "a", "abc");
|
||||
assertEquals("ROOT<V>@1\n", found); // at line 1; shows copy of ID's stuff
|
||||
}
|
||||
|
||||
@Test public void testTreeParserAutoHeteroAST() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID ';' ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {output=AST; ASTLabelType=CommonAST; tokenVocab=T;}\n" +
|
||||
"tokens { ROOT; }\n" +
|
||||
"@members {\n" +
|
||||
"class V extends CommonAST {\n" +
|
||||
" public V(CommonAST t) { super(t); }\n" + // NEEDS SPECIAL CTOR
|
||||
" public String toString() { return super.toString()+\"<V>\";}\n" +
|
||||
"}\n" +
|
||||
"}\n"+
|
||||
"a : ID<V> ';'<V>\n" +
|
||||
" ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "a", "abc;");
|
||||
assertEquals("abc<V> ;<V>\n", found);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2010 Terence Parr
|
||||
* 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;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestRewriteTemplates extends BaseTest {
|
||||
protected boolean debug = false;
|
||||
|
||||
@Test public void testDelete() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : ID INT -> ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("", found);
|
||||
}
|
||||
|
||||
@Test public void testAction() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : ID INT -> {new StringTemplate($ID.text)} ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("abc\n", found);
|
||||
}
|
||||
|
||||
@Test public void testEmbeddedLiteralConstructor() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : ID INT -> {%{$ID.text}} ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("abc\n", found);
|
||||
}
|
||||
|
||||
@Test public void testInlineTemplate() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : ID INT -> template(x={$ID},y={$INT}) <<x:<x.text>, y:<y.text>;>> ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("x:abc, y:34;\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNamedTemplate() throws Exception {
|
||||
// the support code adds template group in it's output Test.java
|
||||
// that defines template foo.
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : ID INT -> foo(x={$ID.text},y={$INT.text}) ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("abc 34\n", found);
|
||||
}
|
||||
|
||||
@Test public void testIndirectTemplate() throws Exception {
|
||||
// the support code adds template group in it's output Test.java
|
||||
// that defines template foo.
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : ID INT -> ({\"foo\"})(x={$ID.text},y={$INT.text}) ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("abc 34\n", found);
|
||||
}
|
||||
|
||||
@Test public void testInlineTemplateInvokingLib() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : ID INT -> template(x={$ID.text},y={$INT.text}) \"<foo(...)>\" ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("abc 34\n", found);
|
||||
}
|
||||
|
||||
@Test public void testPredicatedAlts() throws Exception {
|
||||
// the support code adds template group in it's output Test.java
|
||||
// that defines template foo.
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : ID INT -> {false}? foo(x={$ID.text},y={$INT.text})\n" +
|
||||
" -> foo(x={\"hi\"}, y={$ID.text})\n" +
|
||||
" ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("hi abc\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTemplateReturn() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : b {System.out.println($b.st);} ;\n" +
|
||||
"b : ID INT -> foo(x={$ID.text},y={$INT.text}) ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("abc 34\n", found);
|
||||
}
|
||||
|
||||
@Test public void testReturnValueWithTemplate() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a : b {System.out.println($b.i);} ;\n" +
|
||||
"b returns [int i] : ID INT {$i=8;} ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("8\n", found);
|
||||
}
|
||||
|
||||
@Test public void testTemplateRefToDynamicAttributes() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=template;}\n" +
|
||||
"a scope {String id;} : ID {$a::id=$ID.text;} b\n" +
|
||||
" {System.out.println($b.st.toString());}\n" +
|
||||
" ;\n" +
|
||||
"b : INT -> foo(x={$a::id}) ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abc 34", debug);
|
||||
assertEquals("abc \n", found);
|
||||
}
|
||||
|
||||
// tests for rewriting templates in tree parsers
|
||||
|
||||
@Test public void testSingleNode() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {ASTLabelType=CommonTree; output=template;}\n" +
|
||||
"s : a {System.out.println($a.st);} ;\n" +
|
||||
"a : ID -> template(x={$ID.text}) <<|<x>|>> ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "s", "abc");
|
||||
assertEquals("|abc|\n", found);
|
||||
}
|
||||
|
||||
@Test public void testSingleNodeRewriteMode() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : ID ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+;\n" +
|
||||
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
|
||||
|
||||
String treeGrammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {ASTLabelType=CommonTree; output=template; rewrite=true;}\n" +
|
||||
"s : a {System.out.println(input.getTokenStream().toString(0,0));} ;\n" +
|
||||
"a : ID -> template(x={$ID.text}) <<|<x>|>> ;\n";
|
||||
|
||||
String found = execTreeParser("T.g", grammar, "TParser", "TP.g",
|
||||
treeGrammar, "TP", "TLexer", "a", "s", "abc");
|
||||
assertEquals("|abc|\n", found);
|
||||
}
|
||||
|
||||
@Test public void testRewriteRuleAndRewriteModeOnSimpleElements() throws Exception {
|
||||
String grammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {ASTLabelType=CommonTree; output=template; rewrite=true;}\n" +
|
||||
"a: ^(A B) -> {ick}\n" +
|
||||
" | y+=INT -> {ick}\n" +
|
||||
" | x=ID -> {ick}\n" +
|
||||
" | BLORT -> {ick}\n" +
|
||||
" ;\n";
|
||||
String expecting = null;
|
||||
testErrors(new String[]{grammar, expecting}, false);
|
||||
}
|
||||
|
||||
@Test public void testRewriteRuleAndRewriteModeIgnoreActionsPredicates() throws Exception {
|
||||
String grammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {ASTLabelType=CommonTree; output=template; rewrite=true;}\n" +
|
||||
"a: {action} {action2} x=A -> {ick}\n" +
|
||||
" | {pred1}? y+=B -> {ick}\n" +
|
||||
" | C {action} -> {ick}\n" +
|
||||
" | {pred2}?=> z+=D -> {ick}\n" +
|
||||
" | (E)=> ^(F G) -> {ick}\n" +
|
||||
" ;\n";
|
||||
String expecting = null;
|
||||
testErrors(new String[]{grammar, expecting}, false);
|
||||
}
|
||||
|
||||
@Test public void testRewriteRuleAndRewriteModeNotSimple() throws Exception {
|
||||
String grammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {ASTLabelType=CommonTree; output=template; rewrite=true;}\n" +
|
||||
"a : ID+ -> {ick}\n" +
|
||||
" | INT INT -> {ick}\n" +
|
||||
" ;\n";
|
||||
String expecting = null;
|
||||
testErrors(new String[] {grammar, expecting}, false);
|
||||
}
|
||||
|
||||
@Test public void testRewriteRuleAndRewriteModeRefRule() throws Exception {
|
||||
String grammar =
|
||||
"tree grammar TP;\n"+
|
||||
"options {ASTLabelType=CommonTree; output=template; rewrite=true;}\n" +
|
||||
"a : b+ -> {ick}\n" +
|
||||
" | b b A -> {ick}\n" +
|
||||
" ;\n" +
|
||||
"b : B ;\n";
|
||||
String expecting = null;
|
||||
testErrors(new String[] {grammar, expecting}, false);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2010 Terence Parr
|
||||
* 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;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/** Test the set stuff in lexer and parser */
|
||||
public class TestSets extends BaseTest {
|
||||
protected boolean debug = false;
|
||||
|
||||
/** Public default constructor used by TestRig */
|
||||
public TestSets() {
|
||||
}
|
||||
|
||||
@Test public void testSeqDoesNotBecomeSet() throws Exception {
|
||||
// this must return A not I to the parser; calling a nonfragment rule
|
||||
// from a nonfragment rule does not set the overall token.
|
||||
String grammar =
|
||||
"grammar P;\n" +
|
||||
"a : C {System.out.println(input);} ;\n" +
|
||||
"fragment A : '1' | '2';\n" +
|
||||
"fragment B : '3' '4';\n" +
|
||||
"C : A | B;\n";
|
||||
String found = execParser("P.g", grammar, "PParser", "PLexer",
|
||||
"a", "34", debug);
|
||||
assertEquals("34\n", found);
|
||||
}
|
||||
|
||||
@Test public void testParserSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : t=('x'|'y') {System.out.println($t.text);} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "x", debug);
|
||||
assertEquals("x\n", found);
|
||||
}
|
||||
|
||||
@Test public void testParserNotSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : t=~('x'|'y') 'z' {System.out.println($t.text);} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "zz", debug);
|
||||
assertEquals("z\n", found);
|
||||
}
|
||||
|
||||
@Test public void testParserNotToken() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : ~'x' 'z' {System.out.println(input);} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "zz", debug);
|
||||
assertEquals("zz\n", found);
|
||||
}
|
||||
|
||||
@Test public void testParserNotTokenWithLabel() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : t=~'x' 'z' {System.out.println($t.text);} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "zz", debug);
|
||||
assertEquals("z\n", found);
|
||||
}
|
||||
|
||||
@Test public void testRuleAsSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a @after {System.out.println(input);} : 'a' | 'b' |'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "b", debug);
|
||||
assertEquals("b\n", found);
|
||||
}
|
||||
|
||||
@Test public void testRuleAsSetAST() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options {output=AST;}\n" +
|
||||
"a : 'a' | 'b' |'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "b", debug);
|
||||
assertEquals("b\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNotChar() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println($A.text);} ;\n" +
|
||||
"A : ~'b' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "x", debug);
|
||||
assertEquals("x\n", found);
|
||||
}
|
||||
|
||||
@Test public void testOptionalSingleElement() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A? 'c' {System.out.println(input);} ;\n" +
|
||||
"A : 'b' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "bc", debug);
|
||||
assertEquals("bc\n", found);
|
||||
}
|
||||
|
||||
@Test public void testOptionalLexerSingleElement() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println(input);} ;\n" +
|
||||
"A : 'b'? 'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "bc", debug);
|
||||
assertEquals("bc\n", found);
|
||||
}
|
||||
|
||||
@Test public void testStarLexerSingleElement() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println(input);} ;\n" +
|
||||
"A : 'b'* 'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "bbbbc", debug);
|
||||
assertEquals("bbbbc\n", found);
|
||||
found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "c", debug);
|
||||
assertEquals("c\n", found);
|
||||
}
|
||||
|
||||
@Test public void testPlusLexerSingleElement() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println(input);} ;\n" +
|
||||
"A : 'b'+ 'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "bbbbc", debug);
|
||||
assertEquals("bbbbc\n", found);
|
||||
}
|
||||
|
||||
@Test public void testOptionalSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : ('a'|'b')? 'c' {System.out.println(input);} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "ac", debug);
|
||||
assertEquals("ac\n", found);
|
||||
}
|
||||
|
||||
@Test public void testStarSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : ('a'|'b')* 'c' {System.out.println(input);} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abaac", debug);
|
||||
assertEquals("abaac\n", found);
|
||||
}
|
||||
|
||||
@Test public void testPlusSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : ('a'|'b')+ 'c' {System.out.println(input);} ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abaac", debug);
|
||||
assertEquals("abaac\n", found);
|
||||
}
|
||||
|
||||
@Test public void testLexerOptionalSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println(input);} ;\n" +
|
||||
"A : ('a'|'b')? 'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "ac", debug);
|
||||
assertEquals("ac\n", found);
|
||||
}
|
||||
|
||||
@Test public void testLexerStarSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println(input);} ;\n" +
|
||||
"A : ('a'|'b')* 'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abaac", debug);
|
||||
assertEquals("abaac\n", found);
|
||||
}
|
||||
|
||||
@Test public void testLexerPlusSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println(input);} ;\n" +
|
||||
"A : ('a'|'b')+ 'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "abaac", debug);
|
||||
assertEquals("abaac\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNotCharSet() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println($A.text);} ;\n" +
|
||||
"A : ~('b'|'c') ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "x", debug);
|
||||
assertEquals("x\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNotCharSetWithLabel() throws Exception {
|
||||
// This doesn't work in lexer yet.
|
||||
// Generates: h=input.LA(1); but h is defined as a Token
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println($A.text);} ;\n" +
|
||||
"A : h=~('b'|'c') ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "x", debug);
|
||||
assertEquals("x\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNotCharSetWithRuleRef() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println($A.text);} ;\n" +
|
||||
"A : ~('a'|B) ;\n" +
|
||||
"B : 'b' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "x", debug);
|
||||
assertEquals("x\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNotCharSetWithRuleRef2() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println($A.text);} ;\n" +
|
||||
"A : ~('a'|B) ;\n" +
|
||||
"B : 'b'|'c' ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "x", debug);
|
||||
assertEquals("x\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNotCharSetWithRuleRef3() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println($A.text);} ;\n" +
|
||||
"A : ('a'|B) ;\n" +
|
||||
"fragment\n" +
|
||||
"B : ~('a'|'c') ;\n";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "x", debug);
|
||||
assertEquals("x\n", found);
|
||||
}
|
||||
|
||||
@Test public void testNotCharSetWithRuleRef4() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : A {System.out.println($A.text);} ;\n" +
|
||||
"A : ('a'|B) ;\n" +
|
||||
"fragment\n" +
|
||||
"B : ~('a'|C) ;\n" +
|
||||
"fragment\n" +
|
||||
"C : 'c'|'d' ;\n ";
|
||||
String found = execParser("T.g", grammar, "TParser", "TLexer",
|
||||
"a", "x", debug);
|
||||
assertEquals("x\n", found);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2010 Terence Parr
|
||||
* 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;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.stringtemplate.v4.ST;
|
||||
import org.stringtemplate.v4.STGroup;
|
||||
import org.stringtemplate.v4.STGroupString;
|
||||
|
||||
/** Test templates in actions; %... shorthands */
|
||||
public class TestTemplates extends BaseTest {
|
||||
private static final String LINE_SEP = System.getProperty("line.separator");
|
||||
|
||||
String template =
|
||||
"simpleTemplate(inline) ::= <<\n" +
|
||||
"grammar T;\n" +
|
||||
"options {\n" +
|
||||
" output=template;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"a : ID {#inline#<inline>#end-inline#}\n" +
|
||||
" ;\n" +
|
||||
"\n" +
|
||||
"ID : 'a';\n" +
|
||||
">>\n";
|
||||
|
||||
@Test
|
||||
public void testTemplateConstructor() throws Exception {
|
||||
String action = "x = %foo(name={$ID.text});";
|
||||
String expecting = "x = templateLib.getInstanceOf(\"foo\"," +
|
||||
"new STAttrMap().put(\"name\", (ID1!=null?ID1.getText():null)));";
|
||||
testActions(template, "inline", action, expecting);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemplateConstructorNoArgs() throws Exception {
|
||||
String action = "x = %foo();";
|
||||
String expecting = "x = templateLib.getInstanceOf(\"foo\");";
|
||||
testActions(template, "inline", action, expecting);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndirectTemplateConstructor() throws Exception {
|
||||
String action = "x = %({\"foo\"})(name={$ID.text});";
|
||||
String expecting = "x = templateLib.getInstanceOf(\"foo\"," +
|
||||
"new STAttrMap().put(\"name\", (ID1!=null?ID1.getText():null)));";
|
||||
testActions(template, "inline", action, expecting);
|
||||
}
|
||||
|
||||
@Test public void testStringConstructor() throws Exception {
|
||||
String action = "x = %{$ID.text};";
|
||||
String expecting = "x = new StringTemplate(templateLib,(ID1!=null?ID1.getText():null));";
|
||||
testActions(template, "inline", action, expecting);
|
||||
}
|
||||
|
||||
@Test public void testSetAttr() throws Exception {
|
||||
String action = "%x.y = z;";
|
||||
String expecting = "(x).setAttribute(\"y\", z);";
|
||||
testActions(template, "inline", action, expecting);
|
||||
}
|
||||
|
||||
@Test public void testSetAttrOfExpr() throws Exception {
|
||||
String action = "%{foo($ID.text).getST()}.y = z;";
|
||||
String expecting = "(foo((ID1!=null?ID1.getText():null)).getST()).setAttribute(\"y\", z);";
|
||||
testActions(template, "inline", action, expecting);
|
||||
}
|
||||
|
||||
@Test public void testCannotHaveSpaceBeforeDot() throws Exception {
|
||||
String action = "%x .y = z;";
|
||||
String expecting = ": T.g:6:16: invalid StringTemplate % shorthand syntax: '%x'";
|
||||
STGroup grammarG = new STGroupString(template);
|
||||
ST grammarST = grammarG.getInstanceOf("simpleTemplate");
|
||||
grammarST.add("inline", action);
|
||||
String grammar = grammarST.render();
|
||||
testErrors(new String[] {grammar, expecting}, false);
|
||||
}
|
||||
|
||||
@Test public void testCannotHaveSpaceAfterDot() throws Exception {
|
||||
String action = "%x. y = z;";
|
||||
String expecting = ": T.g:6:16: invalid StringTemplate % shorthand syntax: '%x.'";
|
||||
STGroup grammarG = new STGroupString(template);
|
||||
ST grammarST = grammarG.getInstanceOf("simpleTemplate");
|
||||
grammarST.add("inline", action);
|
||||
String grammar = grammarST.render();
|
||||
testErrors(new String[] {grammar, expecting}, false);
|
||||
}
|
||||
|
||||
// S U P P O R T
|
||||
private void assertNoErrors(ErrorQueue equeue) {
|
||||
assertTrue("unexpected errors: "+equeue, equeue.errors.size()==0);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue