got lots more rewrite ast done including predicates

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 8850]
This commit is contained in:
parrt 2011-07-10 17:07:07 -08:00
parent a06679fec7
commit 1dc598c26e
25 changed files with 451 additions and 196 deletions

View File

@ -106,20 +106,20 @@ public abstract class BaseRecognizer extends Recognizer<ParserInterpreter> {
failed = false;
return matchedSymbol;
}
System.out.println("MATCH failure at state "+_ctx.s+
", ctx="+_ctx.toString(this));
// System.out.println("MATCH failure at state "+_ctx.s+
// ", ctx="+_ctx.toString(this));
IntervalSet expecting = _interp.atn.nextTokens(_ctx);
System.out.println("could match "+expecting);
// System.out.println("could match "+expecting);
matchedSymbol = recoverFromMismatchedToken(ttype, expecting);
System.out.println("rsync'd to "+matchedSymbol);
// System.out.println("rsync'd to "+matchedSymbol);
return matchedSymbol;
}
// like matchSet but w/o consume; error checking routine.
public void sync(IntervalSet expecting) {
if ( expecting.member(input.LA(1)) ) return;
System.out.println("failed sync to "+expecting);
// System.out.println("failed sync to "+expecting);
IntervalSet followSet = computeErrorRecoverySet();
followSet.addAll(expecting);
NoViableAltException e = new NoViableAltException(this, _ctx);

View File

@ -261,7 +261,7 @@ public abstract class BaseTree implements Tree {
throw new IllegalStateException("parents don't match; expected "+parent+" found "+this.getParent());
}
if ( i!=this.getChildIndex() ) {
throw new IllegalStateException("child indexes don't match; expected "+i+" found "+this.getChildIndex());
throw new IllegalStateException("child index of "+this.toStringTree()+" doesn't match in "+parent.toStringTree()+"; expected "+i+" found "+this.getChildIndex());
}
int n = this.getChildCount();
for (int c = 0; c < n; c++) {

View File

@ -1,16 +1,15 @@
grammar T;
options {output=AST;}
tokens {I;}
a : A B -> ^(A B);
a : 'var' (ID ':' type ';')+ -> ^('var' ^(':' ID type)*) ;
atom : A ;
b : B | C ;
type : ID ;
ID : 'a'..'z'+ ;
INT : '0'..'9'+;
WS : (' '|'\n') {$channel=HIDDEN;} ;
/*
c : A B C -> A ( D A B C*)* (B A*)? ;
*/
A : 'a';
B : 'b';
@ -18,6 +17,7 @@ C : 'c';
D : 'd';
SEMI : ';';
WS : ' '|'\t'|'\n' {skip();} ;
*/
/*
r[int a] returns [int b]

View File

@ -131,7 +131,9 @@ CodeBlockForAlt(c, locals, preamble, ops) ::= <<
}
>>
LL1AltBlock(choice, alts, error) ::= <<
LL1AltBlock(choice, preamble, alts, error) ::= <<
<if(choice.label)><labelref(choice.label)> = input.LT(1);<endif>
<preamble; separator="\n">
switch ( input.LA(1) ) {
<choice.altLook,alts:{look,alt| <cases(ttypes=look)>
<alt>
@ -211,7 +213,9 @@ do {
// LL(*) stuff
AltBlock(choice, alts, error) ::= <<
AltBlock(choice, preamble, alts, error) ::= <<
<if(choice.label)><labelref(choice.label)> = input.LT(1);<endif>
<preamble; separator="\n">
switch ( _interp.adaptivePredict(input,<choice.decision>,_ctx) ) {
<alts:{alt |
case <i>:
@ -281,6 +285,11 @@ _localctx.s = <m.stateNumber>;
<if(m.labels)><m.labels:{l | <labelref(l)> = }>(Token)<endif>match(<m.name>);
>>
Wildcard(w) ::= <<
_localctx.s = <w.stateNumber>;
<if(w.labels)><w.labels:{l | <labelref(l)> = }><endif>input.LT(1); input.consume();
>>
// ACTION STUFF
Action(a, chunks) ::= "<chunks>"
@ -381,16 +390,29 @@ ClearElementList(c) ::= "<c.name>.clear();"
TrackRuleElement(e) ::= "<e.name>.add(<labelref(e.label)>.tree);"
TrackTokenElement(e) ::= "<e.name>.add(_adaptor.create(<labelref(e.label)>));"
// REWRITE AST stuff
// assume roots are always locals in tree rewrites
TreeRewrite(tr, locals, preamble, ops) ::= <<
TreeRewrite(tr, locals, preamble, alts) ::= <<
// rewrite: code level= <tr.codeBlockLevel>, tree level = <tr.treeLevel>
<locals; separator="\n">
<preamble; separator="\n">
<ops; separator="\n">
<alts; separator="else\n">
_localctx.tree = _root0;
>>
RewriteChoice(c, predicate, ops) ::= <<
<if(predicate)>
if ( <predicate> ) {
<ops; separator="\n">
}
<else>
{
<ops; separator="\n"> <! empty if EPSILON alt !>
}
<endif>
>>
RewriteIteratorDecl(d) ::= "Iterator <d.name>;"
RewriteIteratorInit(i) ::= "<i.decl.name> = <i.decl.listName>.iterator();"
RewriteIteratorName(elemName,level) ::= "it<level>_<elemName>"

View File

@ -245,7 +245,7 @@ public class ActionTranslator implements ActionSplitterListener {
Class c = tokenPropToModelMap.get(y.getText());
Constructor ctor = c.getConstructor(new Class[] {String.class});
TokenPropertyRef ref =
(TokenPropertyRef)ctor.newInstance(getRuleLabel(x.getText()));
(TokenPropertyRef)ctor.newInstance(getTokenLabel(x.getText()));
return ref;
}
catch (Exception e) {

View File

@ -77,15 +77,19 @@ public abstract class BlankOutputModelFactory implements OutputModelFactory {
public List<SrcOp> rootRule(List<SrcOp> ops) { return ops; }
public List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST) { return null; }
// AST REWRITES
public TreeRewrite treeRewrite(GrammarAST ast) { return null; }
public RewriteChoice rewrite_choice(PredAST pred, List<SrcOp> ops) { return null; }
public RewriteTreeOptional rewrite_optional(GrammarAST ast) { return null; }
public RewriteTreeClosure rewrite_closure(GrammarAST ast) { return null; }
public RewriteTreeStructure rewrite_tree(GrammarAST root) { return null; }
public RewriteTreeStructure rewrite_treeStructure(GrammarAST root) { return null; }
public List<SrcOp> rewrite_ruleRef(GrammarAST ID, boolean isRoot) { return null; }
@ -99,19 +103,21 @@ public abstract class BlankOutputModelFactory implements OutputModelFactory {
public List<SrcOp> rewrite_action(ActionAST action, boolean isRoot) { return null; }
public List<SrcOp> rewrite_epsilon(GrammarAST epsilon) { return null; }
// BLOCKS
public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) { return null; }
public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label) { return null; }
public Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) { return null; }
public Choice getLL1ChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) { return null; }
public Choice getLLStarChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) { return null; }
public Choice getComplexChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) { return null; }
public Choice getLL1EBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) { return null; }
public Choice getLLStarEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) { return null; }
public Choice getComplexEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) { return null; }
public List<SrcOp> getLL1Test(IntervalSet look, GrammarAST blkAST) { return null; }

View File

@ -68,6 +68,7 @@ public class CodeGeneratorExtension {
public List<SrcOp> stringRef(List<SrcOp> ops) { return ops; }
public List<SrcOp> wildcard(List<SrcOp> ops) { return ops; }
// ACTIONS
@ -87,15 +88,35 @@ public class CodeGeneratorExtension {
public List<SrcOp> leafRule(List<SrcOp> ops) { return ops; }
// BLOCKS
public List<SrcOp> getChoiceBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getEBNFBlock(List<SrcOp> ops) { return ops; }
/*
public List<SrcOp> getLL1ChoiceBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getLL1EBNFBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getComplexChoiceBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getComplexEBNFBlock(List<SrcOp> ops) { return ops; }
*/
public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) { return false; }
// AST REWRITEs
public TreeRewrite treeRewrite(TreeRewrite r) { return r; }
public RewriteChoice rewrite_choice(RewriteChoice r) { return r; }
public RewriteTreeOptional rewrite_optional(RewriteTreeOptional o) { return o; }
public RewriteTreeClosure rewrite_closure(RewriteTreeClosure c) { return c; }
public RewriteTreeStructure rewrite_tree(RewriteTreeStructure t) { return t; }
public RewriteTreeStructure rewrite_treeStructure(RewriteTreeStructure t) { return t; }
public List<SrcOp> rewrite_ruleRef(List<SrcOp> ops) { return ops; }
@ -107,21 +128,5 @@ public class CodeGeneratorExtension {
public List<SrcOp> rewrite_action(List<SrcOp> ops) { return ops; }
// BLOCKS
public List<SrcOp> getChoiceBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getEBNFBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getLL1ChoiceBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getLLStarChoiceBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getLL1EBNFBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getLLStarEBNFBlock(List<SrcOp> ops) { return ops; }
public List<SrcOp> getLL1Test(List<SrcOp> ops) { return ops; }
public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) { return false; }
public List<SrcOp> rewrite_epsilon(List<SrcOp> ops) { return ops; }
}

View File

@ -55,6 +55,8 @@ public abstract class DefaultOutputModelFactory extends BlankOutputModelFactory
this.controller = controller;
}
// Convenience methods
public Grammar getGrammar() { return g; }
public CodeGenerator getGenerator() { return gen; }
@ -95,4 +97,3 @@ public abstract class DefaultOutputModelFactory extends BlankOutputModelFactory
}
}

View File

@ -34,7 +34,6 @@ import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.ast.*;
import org.antlr.v4.codegen.model.decl.CodeBlock;
import org.antlr.v4.parse.*;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.*;
import java.util.*;
@ -99,7 +98,7 @@ public class OutputModelController {
e.printStackTrace(System.err);
}
function.ctxType = gen.target.getRuleFunctionContextStructName(r);
function.ctxType = gen.target.getRuleFunctionContextStructName(function);
function.ruleCtx.name = function.ctxType;
function.postamble = rulePostamble(function, r);
@ -237,8 +236,14 @@ public class OutputModelController {
return ops;
}
public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) {
Choice c = delegate.getChoiceBlock(blkAST, alts);
public List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST) {
List<SrcOp> ops = delegate.wildcard(ast, labelAST);
for (CodeGeneratorExtension ext : extensions) ops = ext.wildcard(ops);
return ops;
}
public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label) {
Choice c = delegate.getChoiceBlock(blkAST, alts, label);
List<SrcOp> ops = DefaultOutputModelFactory.list(c);
for (CodeGeneratorExtension ext : extensions) ops = ext.getChoiceBlock(ops);
return c;
@ -251,40 +256,6 @@ public class OutputModelController {
return c;
}
public Choice getLL1ChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) {
Choice c = delegate.getLL1ChoiceBlock(blkAST, alts);
List<SrcOp> ops = DefaultOutputModelFactory.list(c);
for (CodeGeneratorExtension ext : extensions) ops = ext.getLL1ChoiceBlock(ops);
return c;
}
public Choice getLLStarChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) {
Choice c = delegate.getLLStarChoiceBlock(blkAST, alts);
List<SrcOp> ops = DefaultOutputModelFactory.list(c);
for (CodeGeneratorExtension ext : extensions) ops = ext.getLLStarChoiceBlock(ops);
return c;
}
public Choice getLL1EBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
Choice c = delegate.getLL1EBNFBlock(ebnfRoot, alts);
List<SrcOp> ops = DefaultOutputModelFactory.list(c);
for (CodeGeneratorExtension ext : extensions) ops = ext.getLL1EBNFBlock(ops);
return c;
}
public Choice getLLStarEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
Choice c = delegate.getLLStarEBNFBlock(ebnfRoot, alts);
List<SrcOp> ops = DefaultOutputModelFactory.list(c);
for (CodeGeneratorExtension ext : extensions) ops = ext.getLLStarEBNFBlock(ops);
return c;
}
public List<SrcOp> getLL1Test(IntervalSet look, GrammarAST blkAST) {
List<SrcOp> ops = delegate.getLL1Test(look, blkAST);
for (CodeGeneratorExtension ext : extensions) ops = ext.getLL1Test(ops);
return ops;
}
public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) {
boolean needs = delegate.needsImplicitLabel(ID, op);
for (CodeGeneratorExtension ext : extensions) needs |= ext.needsImplicitLabel(ID, op);
@ -299,6 +270,12 @@ public class OutputModelController {
return r;
}
public RewriteChoice rewrite_choice(PredAST pred, List<SrcOp> ops) {
RewriteChoice r = delegate.rewrite_choice(pred, ops);
for (CodeGeneratorExtension ext : extensions) r = ext.rewrite_choice(r);
return r;
}
public RewriteTreeOptional rewrite_optional(GrammarAST ast) {
RewriteTreeOptional o = delegate.rewrite_optional(ast);
for (CodeGeneratorExtension ext : extensions) o = ext.rewrite_optional(o);
@ -311,9 +288,9 @@ public class OutputModelController {
return c;
}
public RewriteTreeStructure rewrite_tree(GrammarAST root) {
RewriteTreeStructure t = delegate.rewrite_tree(root);
for (CodeGeneratorExtension ext : extensions) t = ext.rewrite_tree(t);
public RewriteTreeStructure rewrite_treeStructure(GrammarAST root) {
RewriteTreeStructure t = delegate.rewrite_treeStructure(root);
for (CodeGeneratorExtension ext : extensions) t = ext.rewrite_treeStructure(t);
return t;
}
@ -345,6 +322,12 @@ public class OutputModelController {
return ops;
}
public List<SrcOp> rewrite_epsilon(GrammarAST epsilon) {
List<SrcOp> ops = delegate.rewrite_epsilon(epsilon);
for (CodeGeneratorExtension ext : extensions) ops = ext.rewrite_epsilon(ops);
return ops;
}
public OutputModelObject getRoot() { return root; }
public void setRoot(OutputModelObject root) { this.root = root; }

View File

@ -80,17 +80,19 @@ public interface OutputModelFactory {
List<SrcOp> rootRule(List<SrcOp> ops);
Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts);
List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST);
Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label);
Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts);
Choice getLL1ChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts);
Choice getLLStarChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts);
Choice getComplexChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts);
Choice getLL1EBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts);
Choice getLLStarEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts);
Choice getComplexEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts);
List<SrcOp> getLL1Test(IntervalSet look, GrammarAST blkAST);
@ -102,11 +104,13 @@ public interface OutputModelFactory {
TreeRewrite treeRewrite(GrammarAST ast);
RewriteChoice rewrite_choice(PredAST pred, List<SrcOp> ops);
RewriteTreeOptional rewrite_optional(GrammarAST ast);
RewriteTreeClosure rewrite_closure(GrammarAST ast);
RewriteTreeStructure rewrite_tree(GrammarAST root);
RewriteTreeStructure rewrite_treeStructure(GrammarAST root);
List<SrcOp> rewrite_ruleRef(GrammarAST ID, boolean isRoot);
@ -118,6 +122,8 @@ public interface OutputModelFactory {
List<SrcOp> rewrite_action(ActionAST action, boolean isRoot);
List<SrcOp> rewrite_epsilon(GrammarAST epsilon);
// CONTEXT INFO
OutputModelObject getRoot();

View File

@ -44,6 +44,16 @@ public class ParserASTExtension extends CodeGeneratorExtension {
super(factory);
}
@Override
public List<SrcOp> getChoiceBlock(List<SrcOp> ops) {
Choice choice = (Choice)Utils.find(ops, Choice.class);
Alternative alt = factory.getCurrentAlt();
if ( alt.hasRewrite() && choice.label!=null ) {
trackExplicitLabel(choice.preamble, choice.label, choice);
}
return ops;
}
@Override
public CodeBlockForAlt alternative(CodeBlockForAlt blk) {
Alternative alt = factory.getCurrentAlt();
@ -133,62 +143,89 @@ public class ParserASTExtension extends CodeGeneratorExtension {
CodeBlock blk = factory.getCurrentAlternativeBlock();
String elemListName = factory.getGenerator().target.getElementListName(invokeOp.ast.getText());
blk.addLocalDecl(new ElementListDecl(factory, elemListName));
// track any explicit label like _track_label but not implicit label
if ( !label.isImplicit ) {
String labelListName =
factory.getGenerator().target.getElementListName(label.name);
blk.addLocalDecl(new ElementListDecl(factory, labelListName));
}
// add code to track rule results in _track_r
String trackName = factory.getGenerator().target.getElementListName(invokeOp.ast.getText());
TrackRuleElement t = new TrackRuleElement(factory, invokeOp.ast, trackName, label);
clearTrackingIfSingularLabel(ops, invokeOp, trackName);
ops.add(t);
if ( !label.isImplicit ) {
trackName = factory.getGenerator().target.getElementListName(label.name);
TrackRuleElement t2 = new TrackRuleElement(factory, invokeOp.ast, trackName,
label);
if ( invokeOp.ast.parent.getType() == ANTLRParser.ASSIGN ) {
// if x=A must keep it a single-element list; clear before add
ClearElementList c = new ClearElementList(factory, invokeOp.ast, trackName);
ops.add(c);
}
ops.add(t2);
}
// track any explicit label like _track_label but not implicit label
if ( !label.isImplicit ) trackExplicitLabel(ops, label, invokeOp);
return ops;
}
public List<SrcOp> leafTokenInRewriteAlt(MatchToken matchOp, List<SrcOp> ops) {
public List<SrcOp> leafTokenInRewriteAlt(SrcOp matchOp, List<SrcOp> ops) {
CodeBlock blk = factory.getCurrentAlternativeBlock();
TokenDecl label = (TokenDecl)matchOp.getLabels().get(0);
TokenDecl label = (TokenDecl)((LabeledOp)matchOp).getLabels().get(0);
// First declare tracking lists for elements, labels
// track the named element like _track_A
String elemListName = factory.getGenerator().target.getElementListName(matchOp.ast.getText());
blk.addLocalDecl(new ElementListDecl(factory, elemListName));
// track any explicit label like _track_label but not implicit label
if ( !label.isImplicit ) {
String labelListName =
factory.getGenerator().target.getElementListName(label.name);
blk.addLocalDecl(new ElementListDecl(factory, labelListName));
}
// Now, generate track instructions for element and any labels
// do element
String trackName = factory.getGenerator().target.getElementListName(matchOp.ast.getText());
TrackTokenElement t = new TrackTokenElement(factory, matchOp.ast, trackName,
label);
clearTrackingIfSingularLabel(ops, matchOp, trackName);
ops.add(t);
if ( !label.isImplicit ) { // track all explicit labels
trackName = factory.getGenerator().target.getElementListName(label.name);
TrackTokenElement t2 = new TrackTokenElement(factory, matchOp.ast, trackName,
label);
if ( matchOp.ast.parent.getType() == ANTLRParser.ASSIGN ) {
// if x=A must keep it a single-element list; clear before add
ClearElementList c = new ClearElementList(factory, matchOp.ast, trackName);
ops.add(c);
}
ops.add(t2);
}
if ( !label.isImplicit ) trackExplicitLabel(ops, label, matchOp);
return ops;
}
@Override
public List<SrcOp> wildcard(List<SrcOp> ops) {
Wildcard wild = (Wildcard)Utils.find(ops, Wildcard.class);
Alternative alt = factory.getCurrentAlt();
if ( alt.hasRewrite() ) {
TokenDecl label = (TokenDecl)((LabeledOp)wild).getLabels().get(0);
if ( !label.isImplicit ) trackExplicitLabel(ops, label, wild);
return ops;
}
else {
TokenDecl label = (TokenDecl)wild.getLabels().get(0);
SrcOp treeOp = new TokenAST(factory, wild.ast, label);
String rootName = factory.getGenerator().target.getRootName(0);
SrcOp add = new AddChild(factory, rootName, treeOp);
ops.add(add);
return ops;
}
}
public void trackExplicitLabel(List<SrcOp> ops, Decl label, SrcOp opWithLabel) {
CodeBlock blk = factory.getCurrentAlternativeBlock();
// declare _track_label
String labelListName =
factory.getGenerator().target.getElementListName(label.name);
blk.addLocalDecl(new ElementListDecl(factory, labelListName));
// add elements to _track_label
SrcOp trk;
if ( opWithLabel instanceof InvokeRule ) {
trk = new TrackRuleElement(factory, opWithLabel.ast, labelListName, label);
}
else if ( opWithLabel instanceof Choice ||
opWithLabel instanceof MatchToken ||
opWithLabel instanceof Wildcard )
{
trk = new TrackTokenElement(factory, opWithLabel.ast, labelListName, label);
}
else {
trk = null;
}
clearTrackingIfSingularLabel(ops, opWithLabel, labelListName);
ops.add(trk);
}
public void clearTrackingIfSingularLabel(List<SrcOp> ops, SrcOp opWithLabel, String trackName) {
if ( opWithLabel.ast.parent.getType() == ANTLRParser.ASSIGN ) {
// if x=A must keep it a single-element list; clear before add
ClearElementList c = new ClearElementList(factory, opWithLabel.ast, trackName);
ops.add(c);
}
}
@Override
public List<SrcOp> stringRef(List<SrcOp> ops) { return leafToken(ops); }

View File

@ -82,21 +82,64 @@ public class ParserFactory extends DefaultOutputModelFactory {
return list(invokeOp, listLabelOp);
}
public List<SrcOp> tokenRef(GrammarAST ID, GrammarAST label, GrammarAST args) {
LabeledOp matchOp = new MatchToken(this, (TerminalAST) ID, label);
public List<SrcOp> tokenRef(GrammarAST ID, GrammarAST labelAST, GrammarAST args) {
LabeledOp matchOp = new MatchToken(this, (TerminalAST) ID);
if ( labelAST!=null ) {
String label = labelAST.getText();
TokenDecl d = new TokenDecl(this, label);
((MatchToken)matchOp).labels.add(d);
getCurrentRuleFunction().addContextDecl(d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
TokenListDecl l = new TokenListDecl(this, gen.target.getListLabel(label));
getCurrentRuleFunction().addContextDecl(l);
}
}
if ( controller.needsImplicitLabel(ID, matchOp) ) defineImplicitLabel(ID, matchOp);
AddToLabelList listLabelOp = getListLabelIfPresent(matchOp, label);
AddToLabelList listLabelOp = getListLabelIfPresent(matchOp, labelAST);
return list(matchOp, listLabelOp);
}
public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) {
@Override
public List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST) {
Wildcard wild = new Wildcard(this, ast);
// TODO: dup with tokenRef
if ( labelAST!=null ) {
String label = labelAST.getText();
TokenDecl d = new TokenDecl(this, label);
wild.labels.add(d);
getCurrentRuleFunction().addContextDecl(d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
TokenListDecl l = new TokenListDecl(this, gen.target.getListLabel(label));
getCurrentRuleFunction().addContextDecl(l);
}
}
AddToLabelList listLabelOp = getListLabelIfPresent(wild, labelAST);
return list(wild, listLabelOp);
}
public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST labelAST) {
int decision = ((DecisionState)blkAST.atnState).decision;
Choice c;
if ( AnalysisPipeline.disjoint(g.decisionLOOK.get(decision)) ) {
return getLL1ChoiceBlock(blkAST, alts);
c = getLL1ChoiceBlock(blkAST, alts);
}
else {
return getLLStarChoiceBlock(blkAST, alts);
c = getComplexChoiceBlock(blkAST, alts);
}
if ( labelAST!=null ) { // for x=(...), define x or x_list
String label = labelAST.getText();
TokenDecl d = new TokenDecl(this,label);
c.label = d;
getCurrentRuleFunction().addContextDecl(d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
String listLabel = gen.target.getListLabel(label);
TokenListDecl l = new TokenListDecl(this, listLabel);
getCurrentRuleFunction().addContextDecl(l);
}
}
return c;
}
public Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
@ -114,7 +157,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
return getLL1EBNFBlock(ebnfRoot, alts);
}
else {
return getLLStarEBNFBlock(ebnfRoot, alts);
return getComplexEBNFBlock(ebnfRoot, alts);
}
}
@ -122,7 +165,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
return new LL1AltBlock(this, blkAST, alts);
}
public Choice getLLStarChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) {
public Choice getComplexChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) {
return new AltBlock(this, blkAST, alts);
}
@ -147,7 +190,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
return c;
}
public Choice getLLStarEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
public Choice getComplexEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
int ebnf = 0;
if ( ebnfRoot!=null ) ebnf = ebnfRoot.getType();
Choice c = null;
@ -196,6 +239,14 @@ public class ParserFactory extends DefaultOutputModelFactory {
return tr;
}
@Override
public RewriteChoice rewrite_choice(PredAST pred, List<SrcOp> ops) {
RewriteAction predAction = null;
if ( pred!=null ) predAction = new RewriteAction(this, pred);
RewriteChoice c = new RewriteChoice(this, predAction, ops);
return c;
}
@Override
public RewriteTreeOptional rewrite_optional(GrammarAST ast) {
RewriteTreeOptional o =
@ -237,7 +288,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
}
@Override
public RewriteTreeStructure rewrite_tree(GrammarAST root) {
public RewriteTreeStructure rewrite_treeStructure(GrammarAST root) {
RewriteTreeStructure t = new RewriteTreeStructure(this, root, getTreeLevel(), getCodeBlockLevel());
t.addLocalDecl( new RootDecl(this, getTreeLevel()) );
return t;
@ -298,7 +349,8 @@ public class ParserFactory extends DefaultOutputModelFactory {
Rule r = g.getRule(ID.getText());
if ( r!=null ) {
String implLabel = gen.target.getImplicitRuleLabel(ID.getText());
String ctxName = gen.target.getRuleFunctionContextStructName(r);
String ctxName =
gen.target.getRuleFunctionContextStructName(r);
d = new RuleContextDecl(this, implLabel, ctxName);
((RuleContextDecl)d).isImplicit = true;
}
@ -308,7 +360,8 @@ public class ParserFactory extends DefaultOutputModelFactory {
((TokenDecl)d).isImplicit = true;
}
op.getLabels().add(d);
getCurrentRuleFunction().addLocalDecl(d);
// all labels must be in scope struct in case we exec action out of context
getCurrentRuleFunction().addContextDecl(d);
}
public AddToLabelList getListLabelIfPresent(LabeledOp op, GrammarAST label) {

View File

@ -40,7 +40,7 @@ block[GrammarAST label, GrammarAST ebnfRoot] returns [List<? extends SrcOp> omos
{
if ( alts.size()==1 && ebnfRoot==null) return alts;
if ( ebnfRoot==null ) {
$omos = DefaultOutputModelFactory.list(controller.getChoiceBlock((BlockAST)$blk, alts));
$omos = DefaultOutputModelFactory.list(controller.getChoiceBlock((BlockAST)$blk, alts, $label));
}
else {
$omos = DefaultOutputModelFactory.list(controller.getEBNFBlock($ebnfRoot, alts));
@ -123,8 +123,8 @@ atom[GrammarAST label] returns [List<SrcOp> omos]
| range[label] {$omos = $range.omos;}
| ^(DOT ID terminal[label])
| ^(DOT ID ruleref[label])
| ^(WILDCARD .)
| WILDCARD
| ^(WILDCARD .) {$omos = controller.wildcard($WILDCARD, $label);}
| WILDCARD {$omos = controller.wildcard($WILDCARD, $label);}
| ^(ROOT terminal[label]) {$omos = controller.rootToken($terminal.omos);}
| ^(BANG terminal[label]) {$omos = $terminal.omos;}
| terminal[label] {$omos = $terminal.omos;}
@ -174,22 +174,24 @@ rewrite returns [Rewrite code]
CodeBlock save = controller.getCurrentBlock();
controller.setCurrentBlock($code);
}
predicatedRewrite* nakedRewrite
( (p=predicatedRewrite {$code.alts.add($p.alt);})+
r=nakedRewrite {$code.alts.add($r.alt);}
| r=nakedRewrite {$code.alts.add($r.alt);}
)
{
$code.ops = $nakedRewrite.omos;
controller.setCurrentBlock(save);
controller.codeBlockLevel--;
}
;
predicatedRewrite returns [List<SrcOp> omos]
: ^(ST_RESULT SEMPRED rewriteSTAlt)
| ^(RESULT SEMPRED rewriteTreeAlt)
predicatedRewrite returns [RewriteChoice alt]
: ^(ST_RESULT SEMPRED rewriteSTAlt)
| ^(RESULT SEMPRED rewriteTreeAlt) {$alt = controller.rewrite_choice((PredAST)$SEMPRED, $rewriteTreeAlt.omos);}
;
nakedRewrite returns [List<SrcOp> omos]
nakedRewrite returns [RewriteChoice alt]
: ^(ST_RESULT rewriteSTAlt)
| ^(RESULT rewriteTreeAlt) {$omos = $rewriteTreeAlt.omos;}
| ^(RESULT rewriteTreeAlt) {$alt = controller.rewrite_choice(null, $rewriteTreeAlt.omos);}
;
rewriteTreeAlt returns [List<SrcOp> omos]
@ -199,7 +201,7 @@ rewriteTreeAlt returns [List<SrcOp> omos]
)
{$omos = elems;}
| ETC
| EPSILON
| EPSILON {$omos = controller.rewrite_epsilon($EPSILON);}
;
rewriteTreeElement returns [List<SrcOp> omos]
@ -245,7 +247,7 @@ rewriteTree returns [List<SrcOp> omos]
// controller.codeBlockLevel++;
controller.treeLevel++;
List<SrcOp> elems = new ArrayList<SrcOp>();
RewriteTreeStructure t = controller.rewrite_tree($start);
RewriteTreeStructure t = controller.rewrite_treeStructure($start);
// CodeBlock save = controller.getCurrentBlock();
// controller.setCurrentBlock(t);
}

View File

@ -29,6 +29,7 @@
package org.antlr.v4.codegen;
import org.antlr.v4.codegen.model.RuleFunction;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.runtime.*;
import org.antlr.v4.tool.*;
@ -193,11 +194,30 @@ public class Target {
public String getListLabel(String label) { return label+"_list"; }
public String getRuleFunctionContextStructName(Rule r) {
if ( r.args==null && r.retvals==null && r.scope==null && r.getLabelNames()==null ) {
boolean hasNoExternallyVisibleElements =
r.args==null && r.retvals==null && r.scope==null && r.getLabelNames()==null;
if ( hasNoExternallyVisibleElements ) {
return gen.templates.getInstanceOf("ParserRuleContext").render();
}
return r.name+"_ctx";
}
/** If we know which actual function, we can provide the actual ctx type.
* This will contain implicit labels etc... From outside, though, we
* see only ParserRuleContext unless there are externally visible stuff
* like args, locals, explicit labels, etc...
*/
public String getRuleFunctionContextStructName(RuleFunction function) {
Rule r = function.rule;
boolean hasNoExternallyVisibleElements =
r.args==null && r.retvals==null && r.scope==null && r.getLabelNames()==null;
if ( hasNoExternallyVisibleElements && function.ruleCtx.isEmpty() ) {
return gen.templates.getInstanceOf("ParserRuleContext").render();
}
return r.name+"_ctx";
}
public String getRuleDynamicScopeStructName(String ruleName) {
ST st = gen.templates.getInstanceOf("RuleDynamicScopeStructName");
st.add("ruleName", ruleName);

View File

@ -0,0 +1,47 @@
/*
[The "BSD license"]
Copyright (c) 2011 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.codegen;
import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.tool.GrammarAST;
import java.util.*;
public class Wildcard extends RuleElement implements LabeledOp {
public List<Decl> labels = new ArrayList<Decl>();
public Wildcard(OutputModelFactory factory, GrammarAST ast) {
super(factory, ast);
}
public List<Decl> getLabels() { return labels; }
}

View File

@ -49,9 +49,10 @@ import java.util.*;
*/
public abstract class Choice extends RuleElement {
public int decision = -1;
public Decl label;
@ModelElement public List<CodeBlockForAlt> alts;
@ModelElement public List<SrcOp> preamble;
@ModelElement public List<SrcOp> preamble = new ArrayList<SrcOp>();
public Choice(OutputModelFactory factory,
GrammarAST blkOrEbnfRootAST,
@ -62,7 +63,6 @@ public abstract class Choice extends RuleElement {
}
public void addPreambleOp(SrcOp op) {
if ( preamble==null ) preamble = new ArrayList<SrcOp>();
preamble.add(op);
}

View File

@ -55,8 +55,9 @@ public class InvokeRule extends RuleElement implements LabeledOp {
this.name = ast.getText();
CodeGenerator gen = factory.getGenerator();
Rule r = factory.getGrammar().getRule(name);
ctxName = gen.target.getRuleFunctionContextStructName(r);
ctxName = gen.target.getRuleFunctionContextStructName(factory.getCurrentRuleFunction());
// TODO: move to factory
if ( labelAST!=null ) {
// for x=r, define <rule-context-type> x and list_x
String label = labelAST.getText();

View File

@ -30,8 +30,7 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.*;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.tool.*;
import java.util.*;
@ -41,22 +40,12 @@ public class MatchToken extends RuleElement implements LabeledOp {
public String name;
public List<Decl> labels = new ArrayList<Decl>();
public MatchToken(OutputModelFactory factory, TerminalAST ast, GrammarAST labelAST) {
public MatchToken(OutputModelFactory factory, TerminalAST ast) {
super(factory, ast);
Grammar g = factory.getGrammar();
CodeGenerator gen = factory.getGenerator();
int ttype = g.getTokenType(ast.getText());
name = gen.target.getTokenTypeAsTargetLabel(g, ttype);
if ( labelAST!=null ) { // TODO: move to factory
String label = labelAST.getText();
TokenDecl d = new TokenDecl(factory, label);
labels.add(d);
factory.getCurrentRuleFunction().addContextDecl(d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
TokenListDecl l = new TokenListDecl(factory, gen.target.getListLabel(label));
factory.getCurrentRuleFunction().addContextDecl(l);
}
}
}
public List<Decl> getLabels() { return labels; }

View File

@ -30,10 +30,15 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.ast.RewriteChoice;
import org.antlr.v4.codegen.model.decl.CodeBlock;
import java.util.*;
/** Either an ST or Tree rewrite */
public class Rewrite extends CodeBlock {
@ModelElement public List<RewriteChoice> alts = new ArrayList<RewriteChoice>();
public Rewrite(OutputModelFactory factory, int treeLevel, int codeBlockLevel) {
super(factory, treeLevel, codeBlockLevel);
}

View File

@ -0,0 +1,50 @@
/*
[The "BSD license"]
Copyright (c) 2011 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.codegen.model.ast;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.*;
import java.util.List;
/** A collection of operations possibly with a predicate
* that indicates whether to apply the rewrite.
* This is a single alternative and a list of predicated choices.
*/
public class RewriteChoice extends SrcOp {
@ModelElement public SrcOp predicate;
@ModelElement public List<SrcOp> ops;
public RewriteChoice(OutputModelFactory factory, SrcOp predicate, List<SrcOp> ops) {
super(factory);
this.predicate = predicate;
this.ops = ops;
}
}

View File

@ -0,0 +1,39 @@
/*
[The "BSD license"]
Copyright (c) 2011 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.codegen.model.ast;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.Rewrite;
public class TemplateRewrite extends Rewrite {
public TemplateRewrite(OutputModelFactory factory, int treeLevel, int codeBlockLevel) {
super(factory, treeLevel, codeBlockLevel);
}
}

View File

@ -171,10 +171,11 @@ public class Utils {
return b;
}
/** Find exact object type in list */
/** Find exact object type or sublass of cl in list */
public static Object find(List<?> ops, Class cl) {
for (Object o : ops) {
if ( o.getClass() == cl ) return o;
if ( cl.isInstance(o) ) return o;
// if ( o.getClass() == cl ) return o;
}
return null;
}

View File

@ -83,7 +83,7 @@ block[GrammarAST ebnfRoot] returns [ATNFactory.Handle p]
alternative returns [ATNFactory.Handle p]
@init {List<ATNFactory.Handle> els = new ArrayList<ATNFactory.Handle>();}
: ^(ALT_REWRITE a=alternative .) {$p = $a.p;}
: ^(ALT_REWRITE a=alternative .*) {$p = $a.p;}
| ^(ALT EPSILON) {$p = factory.epsilon($EPSILON);}
| ^(ALT (e=element {els.add($e.p);})+)
{$p = factory.alt(els);}

View File

@ -31,9 +31,9 @@ public void track(GrammarAST t, int level) {
// TODO: visitor would be better here
}
/*
rewrite
start
: predicatedRewrite* nakedRewrite
| rewriteTreeEbnf[0]
;
predicatedRewrite
@ -44,13 +44,6 @@ nakedRewrite
: ^(RESULT rewriteAlt)
;
*/
start
: ^(RESULT rewriteAlt)
| rewriteTreeEbnf[0]
;
rewriteAlt
: rewriteTreeAlt[0]
| ETC

View File

@ -874,7 +874,7 @@ public class TestRewriteAST extends BaseTest {
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer",
"a", "a b", debug);
assertEquals("a b\n", found);
assertEquals("a a b\n", found);
}
@Test public void testOptional() throws Exception {
@ -988,7 +988,6 @@ public class TestRewriteAST extends BaseTest {
}
@Test public void testSetWithLabel() throws Exception {
String grammar =
"grammar T;\n" +
"options { output = AST; } \n" +
@ -1047,7 +1046,7 @@ public class TestRewriteAST extends BaseTest {
execParser("T.g", grammar, "TParser", "TLexer",
"a", "a b 3 4 5", debug);
String expecting =
"org.antlr.runtime.tree.RewriteCardinalityException: token ID";
"org.antlr.v4.runtime.tree.RewriteCardinalityException: size==2 and out of elements";
String found = getFirstLineOfException();
assertEquals(expecting, found);
}
@ -1064,7 +1063,7 @@ public class TestRewriteAST extends BaseTest {
execParser("T.g", grammar, "TParser", "TLexer",
"a", "a b", debug);
String expecting =
"org.antlr.runtime.tree.RewriteCardinalityException: token ID";
"org.antlr.v4.runtime.tree.RewriteCardinalityException: size==2 and out of elements";
String found = getFirstLineOfException();
assertEquals(expecting, found);
}
@ -1081,24 +1080,7 @@ public class TestRewriteAST extends BaseTest {
execParser("T.g", grammar, "TParser", "TLexer",
"a", "3", debug);
String expecting =
"org.antlr.runtime.tree.RewriteEmptyStreamException: token ID";
String found = getFirstLineOfException();
assertEquals(expecting, found);
}
@Test public void testLoopCardinality() throws Exception {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"a : ID? INT -> ID* INT ;\n" +
"op : '+'|'-' ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
execParser("T.g", grammar, "TParser", "TLexer",
"a", "3", debug);
String expecting =
"org.antlr.runtime.tree.RewriteEarlyExitException";
"org.antlr.v4.runtime.tree.RewriteEmptyStreamException: n/a";
String found = getFirstLineOfException();
assertEquals(expecting, found);
}
@ -1116,6 +1098,19 @@ public class TestRewriteAST extends BaseTest {
assertEquals("34\n", found);
}
@Test public void testWildcard2() throws Exception {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"a : ID c+=. c+=. -> $c*;\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 def", debug);
assertEquals("34 def\n", found);
}
// E R R O R S
/*