Package org.jostraca.section

Source Code of org.jostraca.section.PythonIndenter

/*
* Name:    PythonIndenter
* Author:  Richard Rodger
*
* Copyright (c) 2001-2003 Richard Rodger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/


// package
package org.jostraca.section;


// import
import org.jostraca.Property;
import org.jostraca.PropertyPython;

import org.jostraca.util.Standard;
import org.jostraca.util.PropertySet;
import org.jostraca.util.RegExp;
import org.jostraca.util.RegExpException;

import java.util.Vector;
import java.util.StringTokenizer;



/** Indent insert statements properly.
*  Note: tab support is flawed: either use tabs exclusively
*  or use only spaces! In fact this class could really do with a complete
*  rewrite! anyone?
*/
public class PythonIndenter extends Identity {


  // public methods

  /** Modify the Section.
   *  @param pSection     Section to modify.
   *  @param pPropertySet PropertySet which may contain parameters for the modification.
   */
  public Section modify( Section pSection, PropertySet pPropertySet ) throws ModifierException {
    //System.out.println("PI.modify: pSection:"+pSection+" pPropertySet:\n"+pPropertySet);
   
    Section check = checkNulls( pSection, pPropertySet );
    if( null != check ) {
      //System.out.println("PI.modify: null != check");
      return check;
    }

    //if( "declare".equals( pSection.getName() ) ) {
    //   System.out.println("PI.modify: from: section:\n"+pSection.getContent());
    //}

    doInsertIndent( pSection, pPropertySet );

    //if( "declare".equals( pSection.getName() ) ) {
    //  System.out.println("PI.modify: returning: section:\n"+pSection.getContent());
    //}
    return pSection;
  }




  // private methods

  /** Prepend the indent of the section insert marker in the code writer format to
   *  the section text;
   *  @param pSection     Section to indent.
   *  @param pPropertySet PropertySet which may contain parameters for the modification.
   */
  private void doInsertIndent( Section pSection, PropertySet pPropertySet ) throws ModifierException {
    //System.out.println("PI.doInsertIndent start");
   
    String sectionName        = pSection.getName();
    String sectionText        = pSection.getContent();
   

    // perform indent
    StringBuffer    newSectionText = new StringBuffer( 48 * ( 1 + (sectionText.length() / 44) ) );
    StringTokenizer st             = new StringTokenizer( sectionText, Standard.NEWLINE );
    boolean         firstLine      = true;
    Vector          veclines       = new Vector();

    while( st.hasMoreTokens() ) {
      veclines.addElement( st.nextToken() );
    }

    String[] lines    = (String[]) veclines.toArray( new String[] {} );
    int      numLines = lines.length;
    String   line     = null;

    String standardIndent            = pPropertySet.get( PropertyPython.standardIndent );
    String tabAsSpaces               = pPropertySet.get( PropertyPython.tabAsSpaces );
    String nonStatementLineRegExpDef = pPropertySet.get( PropertyPython.nonStatementLineRegExp );
    String controlFlowRegExpDef      = pPropertySet.get( PropertyPython.controlFlowRegExp );
    String pythonInsertPrefix        = pPropertySet.get( Property.lang_InsertPrefix );

    // create regexps
    RegExp nonStatementLineRegExp = null;
    try {
      nonStatementLineRegExp = RegExp.make( nonStatementLineRegExpDef );
    } catch( RegExpException ree ) {
      throw new ModifierException( "Unable to understand regular expression for matching non statement lines: "+
                                   PropertyPython.nonStatementLineRegExp+"="+nonStatementLineRegExpDef
                                   );
    }

    RegExp controlFlowRegExp      = null;
    try {
      controlFlowRegExp      = RegExp.make( controlFlowRegExpDef );
    } catch( RegExpException ree ) {
      throw new ModifierException( "Unable to understand regular expression for matching control flow lines: "+
                                   PropertyPython.controlFlowRegExp+"="+controlFlowRegExpDef
                                   );
    }


    //System.out.println("PI.doInsertIndent: numLines:"                  + numLines);
    //System.out.println("PI.doInsertIndent: standardIndent:"            + standardIndent);
    //System.out.println("PI.doInsertIndent: tabAsSpaces:"               + tabAsSpaces);
    //System.out.println("PI.doInsertIndent: nonStatementLineRegExpDef:" + nonStatementLineRegExpDef);
    //System.out.println("PI.doInsertIndent: controlFlowRegExpDef:"      + controlFlowRegExpDef);
    //System.out.println("PI.doInsertIndent: pythonInsertPrefix:"        + pythonInsertPrefix);

    try {

      String  prev              = "";
      String  prevIndent        = "";
      boolean prevIsControlFlow = false;
      String  next              = "";
      String  nextIndent        = "";

    next_line:
      for( int lineI = 0; lineI < numLines; lineI++ ) {
        //System.out.println("PI.doInsertIndent: lineI:"+lineI+" line: "+lines[lineI]);

        if( -1 == lines[ lineI ].indexOf( pythonInsertPrefix ) ) {
          newSectionText.append( lines[ lineI ] );
          newSectionText.append( Standard.NEWLINE );
          continue next_line;
        }
        //System.out.println("PI.doInsertIndent: _py_insert found");

      // find indent of previous non-empty, non-comment line
        prev       = findStatement( lines, lineI, nonStatementLineRegExp, -1 );
        prevIndent = findIndent( prev, tabAsSpaces );

        if( null == prevIndent ) {
          // no previous indent, so don't change line
          newSectionText.append( lines[ lineI ] );
          newSectionText.append( Standard.NEWLINE );
          continue next_line;
        }

        line = lines[ lineI ];
     
      // i.e. ends in :
        prevIsControlFlow = isControlFlow( prev, controlFlowRegExp );
        //System.out.println( "prev:"+prev+" iscf:"+prevIsControlFlow);

        String newLine = Standard.EMPTY;
        if( prevIsControlFlow ) {
          next       = findStatement( lines, lineI, nonStatementLineRegExp, +1 );
          nextIndent = findIndent( next, tabAsSpaces );
          //System.out.println( "next: "+next+" ni:["+nextIndent+"]");

          if( null == nextIndent ) {
            newLine = makeIndent( line, standardIndent );
            //System.out.println( "1 :"+newLine );
          }
          else {
            if( nextIndent.length() > prevIndent.length() ) {
              // follow other statements in sub block
              newLine = makeIndent( line, nextIndent );
              //System.out.println( "2 :"+newLine );
            } else {
              // single statement in sub block
              newLine = makeIndent( line, prevIndent + standardIndent );
              //System.out.println( "3 :"+newLine );
            }
          }
        }
        else {
          newLine = makeIndent( line, prevIndent );
        }

        //System.out.println( "l :"+line );
        //System.out.println( "nl:"+newLine );

        lines[ lineI ] = newLine;
        newSectionText.append( newLine );
        newSectionText.append( Standard.NEWLINE );
      }

      if( Standard.NEWLINE.length() <= newSectionText.length() ) {
        if( !sectionText.endsWith( Standard.NEWLINE ) ) {
          pSection.setContent( newSectionText.substring(0, newSectionText.length() - Standard.NEWLINE.length() ) );
        } else {
          pSection.setContent( newSectionText.toString() );
        }
      } else {
        pSection.setContent( newSectionText.toString() );
      }

    } catch( RegExpException ree ) {
      throw new ModifierException( ree );
    }

  }



  private String findStatement( String[] pLines
                                ,int     pStartLineIndex
                                ,RegExp  pNonStatementRegExp
                                ,int     pSearchDirection
                                ) throws RegExpException {
    //System.out.println("PI.findStatement: sl:"+pStartLineIndex+" sd:"+pSearchDirection);

    String result   = null;
    int    lineI    = pStartLineIndex + pSearchDirection;
    int    numLines = pLines.length;
    while( -1 < lineI
           && lineI < numLines
           && ( !Standard.EMPTY.equals( pNonStatementRegExp.match( pLines[lineI] ) ) )
           ) {
      lineI += pSearchDirection;
    }
    if( -1 < lineI
        && lineI < numLines
        ) {
      result = pLines[ lineI ];
    }

    //System.out.println("PI.findStatement: result:"+result);
    return result;
  }
 


  /** Return the indent of the line, replacing any tabs with pTabAsSpaces
   */
  private String findIndent( String pLine, String pTabAsSpaces ) {
    //System.out.println("PI.findIndent: pTabAsSpaces:#"+pTabAsSpaces+"# pLine:"+pLine);
    if( null == pLine ) {
      //System.out.println("PI.findIndent: null == pLine, returning null");
      return null;
    }

    String       result   = null;
    boolean      stop     = false;
    StringBuffer indent   = new StringBuffer(8);
    int          numChars = pLine.length();
    for( int charI = 0; charI < numChars; charI++ ) {
      switch( pLine.charAt( charI ) ) {
      case ' ':
        indent.append(' ');
        break;
      case '\t':
        indent.append( pTabAsSpaces );
        break;
      default:
        stop = true;
        break;
      }
      if( stop ) {
        break;
      }
    }
    result = indent.toString();
    //System.out.println("PI.findIndent: result: #"+result+"#");
    return result;
  }



  /** True if statement ends with a :
   *  Deals with comments
   */
  private boolean isControlFlow( String pLine, RegExp pControlFlowRegExp ) throws RegExpException {
    boolean result = ( !Standard.EMPTY.equals( pControlFlowRegExp.match( pLine ) ) );
    //System.out.println("PI.isControlFlow: result:"+result+" line:"+pLine);
    return result;
  }


  /** Set the indent of the given line.
   */
  private String makeIndent( String pLine, String pIndent ) {
    //System.out.println("PI.makeIndent: pIndent:#"+pIndent+"# pLine:"+pLine);
    if( null == pLine ) {
      //System.out.println("PI.makeIndent: null == pLine, returning null");
      return null;
    }

    String  result   = null;
    boolean stop     = false;
    int     numChars = pLine.length();
    int     charI    = 0;
    for( charI = 0; charI < numChars; charI++ ) {
      switch( pLine.charAt( charI ) ) {
      case ' ':
        break;
      case '\t':
        break;
      default:
        stop = true;
        break;
      }
      if( stop ) {
        break;
      }
    }
    result = pIndent + pLine.substring( charI );
    //System.out.println("PI.makeIndent: result:"+result);
    return result;   
  }

}
TOP

Related Classes of org.jostraca.section.PythonIndenter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.