Package org.eclipse.assemblyformatter.ir

Source Code of org.eclipse.assemblyformatter.ir.Formatter

package org.eclipse.assemblyformatter.ir;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.eclipse.assemblyformatter.ir.lowlevel.CharacterLiteral;
import org.eclipse.assemblyformatter.ir.lowlevel.Comment;
import org.eclipse.assemblyformatter.ir.lowlevel.IntegerLiteral;
import org.eclipse.assemblyformatter.ir.lowlevel.LineSeparator;
import org.eclipse.assemblyformatter.ir.lowlevel.Symbol;
import org.eclipse.assemblyformatter.ir.lowlevel.WhiteSpace;
import org.eclipse.assemblyformatter.ir.lowlevel.Comment.Type;
import org.eclipse.assemblyformatter.parsers.IARParser;
import org.eclipse.assemblyformatter.parsers.Parser;
import org.w3c.dom.DOMException;

/**
* General formatting procedure:
* <ol>
* <li>Identification of low-level elements (tokens, using automata).</li>
* <li>Identification of high-level elements (using rules).</li>
* <li>Resizing of white-space sections.</li>
* </ol>
*
*/
public class Formatter {
  private IDocument document;
  private Section base;

  public Formatter(IDocument document) {
    this.document = document;
  }

  public void tokenize() {
    Tokenizer tokenizer = new Tokenizer();
    tokenizer.setContent(document.get());
    base = tokenizer.run();
  }

  /**
   *
   * @throws BadLocationException
   */
  public void parse() throws BadLocationException {
    Parser parser = new IARParser();
    parser.setBase(base);
    parser.setDocument(document);
    parser.run();
  }

  /**
   * Align document content.
   *
   * Call this after parsing.
   *
   * <h3>Aligning procedure</h3>
   * <ol>
   * <li>Determine distances between vertical lines. (Pass through section
   * list and see the longest label, instruction, etc.)</li>
   * <li>Resize white-space sections.</li>
   * </ol>
   *
   * <table border="1" cellpadding="4">
   * <tbody>
   * <tr>
   * <th>WHITE_SPACE between ...</th>
   * <th>WHITE_SPACE length</th>
   * </tr>
   * <tr>
   * <td>LINE_SEPARATOR [+ LABEL] and INSTRUCTION</td>
   * <td>instructionDistance [- LABEL length]</td>
   * </tr>
   * <tr>
   * <td>INSTRUCTION and PARAMETER</td>
   * <td>parameterDistance - INSTRUCTION length</td>
   * </tr>
   * </tbody>
   * </table>
   *
   * TODO Label alignment to column 0
   *
   * @throws BadLocationException
   */
  public void rewrite() throws BadLocationException {
    Section section = null;

    // Determine distances between vertical lines.
    // TODO Case when no label is found
    int instructionDistance = 0;
    int parameterDistance = 0;
    int commentDistance = 0;

    section = base;
    while (section != null) {
      Section nextSection = section.getNextSection();

      final int length = section.getLength();

      if (length > 0) {
        // instruction distance
        if (section instanceof Label) {
          if (instructionDistance < length) {
            instructionDistance = length;
          }
        } else {
          // parameter distance
          if (section instanceof Instruction) {
            if (parameterDistance < length) {
              parameterDistance = length;
            }
          }
          // comment distance
          if (section instanceof Parameter) {
            if (commentDistance < length) {
              commentDistance = length;
            }
          }
        }
      }

      section = nextSection;
    }

    final int reserve = 4;

    // Resize white-space sections.
    section = base;

    while (section != null) {
      Section nextSection = section.getNextSection();

      if (nextSection == null) {
        break; // Exit loop.
      }

      if (section instanceof LineSeparator) {
        // Instruction aligning
        final int distance = instructionDistance + reserve;
        if (nextSection instanceof Label) {
          if (nextSection.nextIs(WhiteSpace.class, Instruction.class)) {
            resize(nextSection,
                (WhiteSpace) Section.getNextIs__staticData(0),
                distance);
          } else {
            if (nextSection.nextIs(Instruction.class)) {
              resize(nextSection, null, distance);
            }
          }
        } else {
          if (section.nextIs(WhiteSpace.class, Instruction.class)) {
            WhiteSpace whiteSpaceSection = (WhiteSpace) Section
                .getNextIs__staticData(0);
            whiteSpaceSection.setVirtualLength(distance);
          }
        }

        // Go forward.
        section = nextSection;
        continue;
      }

      if (section instanceof Instruction) {
        // Parameter aligning
        if (section.nextIs(WhiteSpace.class)) {
          if (nextSection.nextIs(Parameter.class)) {
            resize(section, (WhiteSpace) nextSection,
                parameterDistance + reserve);
          } else {
            // Comment aligning
            if (nextSection.nextIs(Comment.class)) {
              resize(section, (WhiteSpace) nextSection,
                  parameterDistance + reserve
                      + commentDistance + reserve);
            }
          }
        }

        // Go forward.
        section = nextSection;
        continue;

      }

      if (section instanceof Parameter) {
        // Comment aligning
        final int distance = commentDistance + reserve;
        if (section.nextIs(WhiteSpace.class, Comment.class)) {
          resize(section, (WhiteSpace) nextSection, distance);
        }
      }

      section = nextSection;
    }

    // Connect position objects to document.
    section = base;
    while (section != null) {
      Section nextSection = section.getNextSection();
      try {
        document.addPosition(section.getPosition());
      } catch (BadLocationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      section = nextSection;
    }

    // Rewrite white-space sections.
    section = base;
    while (section != null) {
      Section nextSection = section.getNextSection();
      if (section instanceof WhiteSpace) {
        WhiteSpace whiteSpace = (WhiteSpace) section;
        if (whiteSpace.getVirtualLength() >= 0) {
          int offset = whiteSpace.getOffset();
          int length = whiteSpace.getLength();
          String text = whiteSpace.getVirtualString();
          try {
            document.replace(offset, length, text);
          } catch (BadLocationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
      }
      section = nextSection;
    }

    // Normalize comments.
    // In case ;... make ; ...
    int offset;
    section = base;
    while (section != null) {
      Section nextSection = section.getNextSection();
      if (section instanceof Comment) {
        Comment comment = (Comment) section;
        switch (comment.getType()) {
        case A:
          offset = comment.getOffset() + 1;
          if (document.getChar(offset) != ' ') {
            document.replace(offset, 0, " ");
          }
          break;
        case CPP:
          offset = comment.getOffset() + 2;
          if (document.getChar(offset) != ' ') {
            document.replace(offset, 0, " ");
          }
          break;
        }
      }
      section = nextSection;
    }

    // Disconnect position objects from document.
    section = base;
    while (section != null) {
      Section nextSection = section.getNextSection();
      document.removePosition(section.getPosition());
      section = nextSection;
    }
  }

  /**
   *
   * @param section
   * @param whiteSpace
   *            can be null
   * @param whiteSpaceLength
   */
  private void resize(Section section, WhiteSpace whiteSpace,
      int whiteSpaceLength) {
    final int sectionLength = section.getLength();

    // Null WHITE_SPACE section case.
    if (whiteSpace == null) {
      whiteSpace = new WhiteSpace();
      whiteSpace.setOffset(section.getOffset() + sectionLength);
      whiteSpace.setLength(0);
      whiteSpace.setNextSection(section.getNextSection());
      section.setNextSection(whiteSpace);
    }

    whiteSpace.setVirtualLength(whiteSpaceLength - sectionLength);
  }

  /**
   * Writes the content of the linked list of document sections obtained after
   * run().
   *
   * This is for verification/debugging purposes.
   *
   * @throws ParserConfigurationException
   * @throws IOException
   * @throws TransformerException
   */
  public void writeSectionList(String filename)
      throws ParserConfigurationException, IOException,
      TransformerException {
    PrintWriter outputStream = null;
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory
          .newInstance();

      DocumentBuilder builder = factory.newDocumentBuilder();
      org.w3c.dom.Document domDocument;
      domDocument = builder.newDocument();

      // Set document content
      org.w3c.dom.Element elementDocument = domDocument
          .createElement("document");
      domDocument.appendChild(elementDocument);

      Section section = base;
      while (section != null) {
        Section nextSection = section.getNextSection();
        org.w3c.dom.Element elementSection = domDocument
            .createElement(section.getClass().getSimpleName());

        org.w3c.dom.CDATASection cdata;
        String sectionContent;
        try {
          sectionContent = section.getContent(document);
        } catch (BadLocationException e) {
          sectionContent = e.getClass().getSimpleName();
        }
        cdata = domDocument.createCDATASection(sectionContent);

        elementSection.setAttribute("offset",
            Integer.toString(section.getOffset()));
        elementSection.setAttribute("length",
            Integer.toString(section.getLength()));

        if (section instanceof WhiteSpace) {
          WhiteSpace whiteSpace = (WhiteSpace) section;
          if (whiteSpace.getVirtualLength() >= 0) {
            elementSection
                .setAttribute("virtualLength",
                    Integer.toString(whiteSpace
                        .getVirtualLength()));
          }
        }

        elementSection.appendChild(cdata);
        elementDocument.appendChild(elementSection);
        section = nextSection;
      }

      // Use a Transformer for output
      TransformerFactory tFactory = TransformerFactory.newInstance();
      Transformer transformer = tFactory.newTransformer();

      DOMSource source = new DOMSource(domDocument);

      outputStream = new PrintWriter(new FileWriter(filename));

      StreamResult result = new StreamResult(outputStream);
      transformer.transform(source, result);
    } catch (ParserConfigurationException e) {
      throw e;
    } catch (IOException e) {
      throw e;
    } catch (TransformerConfigurationException e) {
      throw e;
    } catch (TransformerException e) {
      throw e;
    } finally {
      if (outputStream != null) {
        outputStream.close();
      }
    }
  }

  /**
   * This procedure replaces any TAB character in the document with a fixed
   * number of space characters. Call this procedure before tokenization.
   *
   * @throws BadLocationException
   */
  public void replaceAnyTab(final int spaceCharCount)
      throws BadLocationException {
    if (spaceCharCount > (1 << 5)/* Maximum allowed space characters */) {
      // Error
      return;
    }

    StringBuilder strBuilder = new StringBuilder();
    for (int i = 0; i < spaceCharCount; i++) {
      strBuilder.append(' ');
    }
    final String space = strBuilder.toString();

    for (int offset = 0; offset < document.getLength(); offset++) {
      if (document.getChar(offset) == '\t') {
        document.replace(offset, 1, space);
        offset += spaceCharCount - 1; // Jump over the space inserted
      }
    }
  }
}
TOP

Related Classes of org.eclipse.assemblyformatter.ir.Formatter

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.