Search code examples
javakotlintext-parsing

How to detect the end of a method body of a java file using kotlin?


Let's say we have a java file that looks like this :

class Something {

   public static void main(String[] args){
      
      System.out.println("Hello World!");
   
   }

}

I would like to write some Kotlin code that would go through this java file and detect how many lines there is in the method body (Here is the main method only). Empty lines are counted!

My approach is to simply use the File forEachline method to read the java file line by line. I can write code to detect the method signature. Now I want to be able to determine where the method ends. I don't know how to do that.

If I simply look for "}" my code could make mistakes assuming that we are at the end of the body of the method while in reality we are at the end of an if statement body within the method.

How can I avoid this pitfall?


Solution

  • One way to approach this is keeping track of the number of open brackets('{') and close brackets ('}') seen. At the start of the method, the count will increment to 1. Assuming the method is validly structured, at the end of the method the number of unclosed brackets should be 0. Pseudocode like this should work:

    int numLines = 1 (assuming method start line counts)
    int numBrackets = 1 (after finding method open bracket for method)
    while(numBrackets > 0)
        if char = '{' -> numBrackets++
        if char = '}' -> numBrackets--
        if char = newline -> numLines++
    if numBrackets not 0 -> FAIL
    return numLines
    

    Edit

    As noted by Gidds below, this pseudo-code is insufficient. A more complete answer will need to include the fact that not all brackets impact method structure. One way to approach this is by keeping track of the context of the current character being parsed. Only increment/decrement numBrackets when in a valid context (non-string literal, comment, etc..). Though as noted by Gidds, this will increase complexity. Updated Pseudocode:

    int numLines = 1
    int numValidBrackets = 1
    Context context = Context(MethodStructure)
    while(numValidBrackets > 0)
        context.acceptNextChar(char)
        if char = newline -> numLines++
        if(context.state() != MethodStructure) continue;
        if char = '{' -> numValidBrackets++
        if char = '}' -> numValidBrackets--
    if numBrackets not 0 -> FAIL
    return numLines