Tuesday, February 1, 2011

ANTLR - insert current indent - rewrite multiple lines

See ANTLR4 for other solution using Listener
https://theantlrguy.atlassian.net/wiki/display/ANTLR4/Parse+Tree+Listeners
http://media.pragprog.com/titles/tpantlr2/listener.pdf

Get current indent from token stream using direct Java access to token stream - get all token on HIDDEN channel on current line
How do I access hidden tokens from parser?
http://www.antlr.org/wiki/pages/viewpage.action?pageId=557063



        int startIndex = input.getTreeAdaptor().getTokenStartIndex(retval.start);
        int stopIndex = input.getTreeAdaptor().getTokenStopIndex(retval.start);
        int line = ((Token) input.getTokenStream().get(startIndex)).getLine();
        System.out.println("\nLINE: line" + line + " retval.start" + startIndex + " stop=" + stopIndex);  

        int currentIndex = stopIndex;
        Token token;
        // print all tokens on line
        while (currentIndex >= startIndex &&
                (token = (Token) input.getTokenStream().get(currentIndex)).getLine() == line
        ) {
            System.out.println("currentIndex=" + currentIndex +
                    " line=" + token.getLine() +
                    " token" + token);
            currentIndex--;
        }

        // set current to indent whitespace
        currentIndex = startIndex - 1;
        System.out.println("START: currentIndex=" + currentIndex);

        StringBuffer indent = new StringBuffer();
        while (currentIndex > -1 &&  (token = (Token) input.getTokenStream().get(currentIndex)).getChannel() == Parser.HIDDEN ) {
            System.out.println("INDENT: currentIndex=" + currentIndex + "channel=" +
                    token.getChannel() + " text" + token.getText()
                    + " type=" + token.getType());
            if(token.getText().matches("[\t ]+")){
                indent.append(token.getText());
            }
            currentIndex--;
        }
        if(indent.length() > 0){
            ((primaryExpression_scope) primaryExpression_stack.peek()).indent = indent.toString();

        } else {
            ((primaryExpression_scope) primaryExpression_stack.peek()).indent = "";
        }



Pass current indent to StringTemplate using scope variable
primaryExpression
scope {
  boolean isMethodCall;
  String indent;
}


Rewrite rule
|   ^(METHOD_CALL  primaryExpression {$primaryExpression::isMethodCall=true;} genericTypeArgumentList? arguments)
     
       {
         // Java code inserted here
       }
        -> 
      methodCall(indent={$primaryExpression::indent}, methodCallText={$text})


StringTemplate
group Java;

methodCall(indent,methodCallText) ::= <<
<methodCallText>
<indent>log("Called <methodCallText>")
>>


Log output - getting indent and rewritten HelloWorld program
LINE: line15 retval.start69 stop=72
currentIndex=72 line=15 token[@72,217:217=')',<43>,15:9]
currentIndex=71 line=15 token[@71,216:216='x',<164>,15:8]
currentIndex=70 line=15 token[@70,215:215='(',<29>,15:7]
currentIndex=69 line=15 token[@69,210:214='print',<164>,15:2]
START: currentIndex=68
INDENT: currentIndex=68channel=99 text     type=180
INDENT: currentIndex=67channel=99 text     type=180
INDENT: currentIndex=66channel=99 text
 type=180
INDENT: currentIndex=65channel=99 text  type=180

LINE: line17 retval.start78 stop=85
currentIndex=85 line=17 token[@85,256:256=')',<43>,17:35]
currentIndex=84 line=17 token[@84,242:255='"Hello,world!"',<170>,17:21]
currentIndex=83 line=17 token[@83,241:241='(',<29>,17:20]
currentIndex=82 line=17 token[@82,234:240='println',<164>,17:13]
currentIndex=81 line=17 token[@81,233:233='.',<15>,17:12]
currentIndex=80 line=17 token[@80,230:232='out',<164>,17:9]
currentIndex=79 line=17 token[@79,229:229='.',<15>,17:8]
currentIndex=78 line=17 token[@78,223:228='System',<164>,17:2]
START: currentIndex=77
INDENT: currentIndex=77channel=99 text     type=180
INDENT: currentIndex=76channel=99 text     type=180
INDENT: currentIndex=75channel=99 text
 type=180
INDENT: currentIndex=74channel=99 text
 type=180

LINE: line22 retval.start112 stop=119
currentIndex=119 line=22 token[@119,323:323=')',<43>,22:22]
currentIndex=118 line=22 token[@118,322:322='x',<164>,22:21]
currentIndex=117 line=22 token[@117,321:321='(',<29>,22:20]
currentIndex=116 line=22 token[@116,314:320='println',<164>,22:13]
currentIndex=115 line=22 token[@115,313:313='.',<15>,22:12]
currentIndex=114 line=22 token[@114,310:312='out',<164>,22:9]
currentIndex=113 line=22 token[@113,309:309='.',<15>,22:8]
currentIndex=112 line=22 token[@112,303:308='System',<164>,22:2]
START: currentIndex=111
INDENT: currentIndex=111channel=99 text     type=180
INDENT: currentIndex=110channel=99 text     type=180
INDENT: currentIndex=109channel=99 text
 type=180

Tokens:

public class HelloWorld {

    static int x;

    /**
     * This is test class for ANTLR Java source code transformation
     * @param args
     */
    public static void main(String args[]) {

        int x;
        int y;
        
        x = 1; 
        print(x)
         log("Called print(x)");

        System.out.println("Hello,world!")
        log("Called System.out.println("Hello,world!")");

    }
    
    private static  void print(int x){
        System.out.println(x)
        log("Called System.out.println(x)");
    }

}

No comments:

Post a Comment