title: Once grammar is complete, what's the best way to walk an ANTLR v4 tree?
body: <p><strong>Goal</strong></p>
  
  <p>I'm working on a project to create a Varscoper for Coldfusion CFscript. Basically, this means checking through source code files to ensure that developers have properly <code>var</code>'d their variables.</p>
  
  <p>After a couple of days of working with ANTLR V4 I have a grammar which generates a very nice parse tree in the GUI view. Now, using that tree I need a way to crawl up and down the nodes programmatically looking for variable declarations and ensure that if they are inside functions they have the proper scoping. If possible I would rather NOT do this in the grammar file as that would require mixing the definition of the language with this specific task.</p>
  
  <p><strong>What I've tried</strong></p>
  
  <p>My latest attempt was using the <code>ParserRuleContext</code> and attempting to go through it's <code>children</code> via <code>getPayload()</code>. After checking the class of <code>getPayLoad()</code> I would either have a <code>ParserRuleContext</code> object or a <code>Token</code> object. Unfortunately, using that I was never able to find a way to get the actual rule type for a specific node, only it's containing text. The rule type for each node is neccessary because it matters whether that text node is an ignored right-hand expression, a variable assignment or a function declaration.</p>
  
  <p><strong>Questions</strong></p>
  
  <ol>
  <li>I am very new to ANTLR, is this even the right approach, or is there a better way to traverse the tree?</li>
  </ol>
  
  <p>Here's my sample java code:</p>
  
  <p>Cfscript.java</p>
  
  <pre><code>import org.antlr.v4.runtime.*;
  import org.antlr.v4.runtime.tree.Trees;
  
  public class Cfscript {
      public static void main(String[] args) throws Exception {
          ANTLRInputStream input = new ANTLRFileStream(args[0]);
          CfscriptLexer lexer = new CfscriptLexer(input);
          CommonTokenStream tokens = new CommonTokenStream(lexer);
          CfscriptParser parser = new CfscriptParser(tokens);
          parser.setBuildParseTree(true);
          ParserRuleContext tree = parser.component();
          tree.inspect(parser); // show in gui
          /*
              Recursively go though tree finding function declarations and ensuring all variableDeclarations are varred
              but how?
          */
      }
  }
  </code></pre>
  
  <p>Cfscript.g4</p>
  
  <pre><code>grammar Cfscript;
  
  component
      : 'component' keyValue* '{' componentBody '}'
      ;
  
  componentBody
      : (componentElement)*
      ;
  
  componentElement
      : statement
      | functionDeclaration
      ;
  
  functionDeclaration
      : Identifier? Identifier? 'function' Identifier argumentsDefinition '{' functionBody '}'
      ;
  
  argumentsDefinition
      : '(' argumentDefinition (',' argumentDefinition)* ')'
      | '()'
      ;
  
  argumentDefinition
      : Identifier? Identifier? argumentName ('=' expression)?
      ; 
  
  argumentName
      : Identifier
      ;
  
  functionBody
      : (statement)*
      ;
  
  statement
      : variableStatement
      | nonVarVariableStatement
      | expressionStatement
      ;
  
  variableStatement
      : 'var' variableName '=' expression ';'
      ;
  
  nonVarVariableStatement
      : variableName '=' expression ';'
      ;
  
  expressionStatement
      : expression ';'
      ;
  
  expression
      : assignmentExpression
      | arrayLiteral
      | objectLiteral
      | StringLiteral
      | incrementExpression
      | decrementExpression
      | 'true' 
      | 'false'
      | Identifier
      ;
  
  incrementExpression
      : variableName '++'
      ;
  
  decrementExpression
      : variableName '--'
      ;
  
  assignmentExpression
      : Identifier (assignmentExpressionSuffix)*
      | assignmentExpression (('+'|'-'|'/'|'*') assignmentExpression)+
      ;
  
  assignmentExpressionSuffix
      : '.' assignmentExpression
      | ArrayIndex
      | ('()' | '(' expression (',' expression)* ')' )
      ;
  
  methodCall
      : Identifier ('()' | '(' expression (',' expression)* ')' )
      ;
  
  variableName
      : Identifier (variableSuffix)*
      ;
  
  variableSuffix
      : ArrayIndex
      | '.' variableName
      ;
  
  arrayLiteral
      : '[' expression (',' expression)* ']'
      ;
  
  objectLiteral
      : '{' (Identifier '=' expression (',' Identifier '=' expression)*)? '}'
      ;
  
  keyValue
      : Identifier '=' StringLiteral
      ;
  
  StringLiteral
      :  '"' (~('\\'|'"'))* '"'
      ;
  
   ArrayIndex
      : '[' [1-9] [0-9]* ']'
      | '[' StringLiteral ']'
      ;
  
  Identifier
      : [a-zA-Z0-9]+
      ;
  
  WS
      : [ \t\r\n]+ -&gt; skip 
      ;
  
  COMMENT 
      : '/*' .*? '*/'  -&gt; skip
      ;
  </code></pre>
  
  <p>Test.cfc (testing code file)</p>
  
  <pre><code>component something = "foo" another = "more" persistent = "true" datasource = "#application.env.dsn#" {
      var method = something.foo.test1;
      testing = something.foo[10];
      testingagain = something.foo["this is a test"];
      nuts["testing"]++;
      blah.test().test3["test"]();
  
      var math = 1 + 2 - blah.test().test4["test"];
  
      var test = something;
      var testing = somethingelse;
      var testing = { 
          test = more, 
          mystuff = { 
              interior = test 
          },
          third = "third key"
      };
      other = "Idunno homie";
      methodCall(interiorMethod());
  
      public function bar() {
          var new = "somebody i used to know";
          something = [1, 2, 3];
      }
  
      function nuts(required string test1 = "first", string test = "second", test3 = "third") {
  
      }
  
      private boolean function baz() {
          var this = "something else";
      }
  }
  </code></pre>