Package org.objectstyle.wolips.wodclipse.core.document

Source Code of org.objectstyle.wolips.wodclipse.core.document.DocumentWodModel$ForgivingStack

/*
* ====================================================================
*
* The ObjectStyle Group Software License, Version 1.0
*
* Copyright (c) 2005 The ObjectStyle Group and individual authors of the
* software. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: 1.
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. The end-user documentation
* included with the redistribution, if any, must include the following
* acknowlegement: "This product includes software developed by the ObjectStyle
* Group (http://objectstyle.org/)." Alternately, this acknowlegement may
* appear in the software itself, if and wherever such third-party
* acknowlegements normally appear. 4. The names "ObjectStyle Group" and
* "Cayenne" must not be used to endorse or promote products derived from this
* software without prior written permission. For written permission, please
* contact andrus@objectstyle.org. 5. Products derived from this software may
* not be called "ObjectStyle" nor may "ObjectStyle" appear in their names
* without prior written permission of the ObjectStyle Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* OBJECTSTYLE GROUP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the ObjectStyle Group. For more information on the ObjectStyle
* Group, please see <http://objectstyle.org/> .
*/
package org.objectstyle.wolips.wodclipse.core.document;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.objectstyle.wolips.bindings.wod.AbstractWodModel;
import org.objectstyle.wolips.bindings.wod.IWodBinding;
import org.objectstyle.wolips.bindings.wod.IWodElement;
import org.objectstyle.wolips.bindings.wod.IWodModel;
import org.objectstyle.wolips.bindings.wod.IWodUnit;
import org.objectstyle.wolips.bindings.wod.SimpleWodElement;
import org.objectstyle.wolips.bindings.wod.WodElementProblem;
import org.objectstyle.wolips.bindings.wod.WodProblem;
import org.objectstyle.wolips.wodclipse.core.Activator;
import org.objectstyle.wolips.wodclipse.core.completion.WodCacheEntry;
import org.objectstyle.wolips.wodclipse.core.completion.WodParserCache;
import org.objectstyle.wolips.wodclipse.core.parser.AssignmentOperatorWordDetector;
import org.objectstyle.wolips.wodclipse.core.parser.BindingNameRule;
import org.objectstyle.wolips.wodclipse.core.parser.BindingValueNamespaceRule;
import org.objectstyle.wolips.wodclipse.core.parser.BindingValueRule;
import org.objectstyle.wolips.wodclipse.core.parser.CloseDefinitionWordDetector;
import org.objectstyle.wolips.wodclipse.core.parser.ElementNameRule;
import org.objectstyle.wolips.wodclipse.core.parser.ElementTypeOperatorWordDetector;
import org.objectstyle.wolips.wodclipse.core.parser.ElementTypeRule;
import org.objectstyle.wolips.wodclipse.core.parser.EndAssignmentWordDetector;
import org.objectstyle.wolips.wodclipse.core.parser.ICommentRule;
import org.objectstyle.wolips.wodclipse.core.parser.OpenDefinitionWordDetector;
import org.objectstyle.wolips.wodclipse.core.parser.RulePosition;
import org.objectstyle.wolips.wodclipse.core.parser.StringLiteralRule;
import org.objectstyle.wolips.wodclipse.core.parser.WOOGNLRule;
import org.objectstyle.wolips.wodclipse.core.parser.WodScanner;

/**
* @author mschrag
*/
public class DocumentWodModel extends AbstractWodModel {
  private IFile _wodFile;

  private IDocument _document;

  public DocumentWodModel(IFile wodFile, IDocument document) {
    _wodFile = wodFile;
    _document = document;
    parse();
  }

  public IDocument getDocument() {
    return _document;
  }

  public void addParseProblem(IWodElement element, String message, RulePosition rulePosition, boolean warning) {
    Position position = rulePosition.getPosition();
    try {
      int lineNumber = _document.getLineOfOffset(position.getOffset());
      WodProblem problem;
      if (element != null) {
        problem = new WodElementProblem(element, message, position, lineNumber, warning);
      }
      else {
        problem = new WodProblem(message, position, lineNumber, warning);
      }
      addParseProblem(problem);
    }
    catch (BadLocationException e) {
      Activator.getDefault().log(e);
    }
  }

  // MS: all these savedRulePositions should be switched to instead use the rulePositions stack ...
  protected synchronized void parse() {
    clear();

    WodScanner scanner = WodScanner.wodScannerForDocument(_document);
    DocumentWodBinding lastBinding = null;
    DocumentWodElement element = null;
    RulePosition tentativeElementName = null;
    RulePosition savedRulePosition = null;
    RulePosition savedRulePosition2 = null;
    RulePosition savedRulePosition3 = null;
    RulePosition lastRulePosition = null;
    ForgivingStack<RulePosition> rulePositions = new ForgivingStack<RulePosition>();
    // boolean stringLiteralIsABindingName = false;
    RulePosition rulePosition;
    while ((rulePosition = scanner.nextRulePosition()) != null) {
      boolean whitespace = false;
      boolean comment = false;
      if (RulePosition.isRulePositionOfType(rulePosition, WhitespaceRule.class)) {
        whitespace = true;
      }
      else if (RulePosition.isRulePositionOfType(rulePosition, ICommentRule.class)) {
        comment = true;
        if (lastBinding != null) {
          String commentText = rulePosition._getTextWithoutException();
          if (commentText != null && commentText.startsWith("//")) {
            commentText = commentText.substring(2).trim();
            if ("VALID".equalsIgnoreCase(commentText)) {
              lastBinding.setValidate(false);
            }
          }
        }
        else {
          String commentText = rulePosition._getTextWithoutException();
          if (commentText != null && commentText.startsWith("//")) {
            commentText = commentText.substring(2).trim();
            if (commentText.toLowerCase().startsWith("inherit ")) {
              String componentName = commentText.substring("inherit ".length()).trim();
              try {
                WodParserCache inheritCache = WodParserCache.parser(_wodFile.getProject(), componentName);
                WodCacheEntry wodCacheEntry = inheritCache.getWodEntry();
                IWodModel parentWodModel = wodCacheEntry.getModel();
                for (IWodElement parentWodElement : parentWodModel.getElements()) {
                  SimpleWodElement inheritedWodElement = new SimpleWodElement(parentWodElement);
                  inheritedWodElement.setInherited(true);
                  addElement(inheritedWodElement);
                }
              }
              catch (Throwable t) {
                addParseProblem(element, "WOD inheritance of '" + componentName + "' failed: " + t.getMessage() + ".", rulePosition, false);
              }
            }
          }
        }
      }
      else if (RulePosition.isRulePositionOfType(rulePosition, ElementNameRule.class)) {
        if (RulePosition.isOperatorOfType(lastRulePosition, OpenDefinitionWordDetector.class) || RulePosition.isOperatorOfType(lastRulePosition, EndAssignmentWordDetector.class)) {
          savedRulePosition2 = rulePosition;
          if (lastRulePosition != null && !RulePosition.isOperatorOfType(lastRulePosition, CloseDefinitionWordDetector.class)) {
            tentativeElementName = rulePosition;
          }
          // leave old savedRulePosition
        }
        else {
          if (lastRulePosition != null && !RulePosition.isOperatorOfType(lastRulePosition, CloseDefinitionWordDetector.class)) {
            addParseProblem(element, "The element name '" + rulePosition._getTextWithoutException() + "' must start a WOD declaration", rulePosition, false);
          }
          savedRulePosition = rulePosition;
          element = null;
        }
      }
      else if (RulePosition.isOperatorOfType(rulePosition, ElementTypeOperatorWordDetector.class)) {
        if (!RulePosition.isRulePositionOfType(lastRulePosition, ElementNameRule.class) && !RulePosition.isRulePositionOfType(lastRulePosition, BindingValueNamespaceRule.class)) {
          addParseProblem(element, "A ':' can only appear after an element name or a binding value namespace.", rulePosition, false);
        }
      }
      else if (RulePosition.isRulePositionOfType(rulePosition, ElementTypeRule.class)) {
        if (tentativeElementName != null) {
           addParseProblem(element, "The element name ' " + tentativeElementName._getTextWithoutException() + "' must start a WOD declaration", tentativeElementName, false);
          tentativeElementName = null;
          savedRulePosition = null;
        }
        else if (!RulePosition.isOperatorOfType(lastRulePosition, ElementTypeOperatorWordDetector.class)) {
          addParseProblem(element, "The element type '" + rulePosition._getTextWithoutException() + "' can only appear after a ':'", rulePosition, false);
        }
        else {
          rulePositions.clear();
          element = new DocumentWodElement(savedRulePosition, rulePosition);
          addElement(element);
          savedRulePosition = null;
        }
      }
      else if (RulePosition.isOperatorOfType(rulePosition, OpenDefinitionWordDetector.class)) {
        if (!RulePosition.isRulePositionOfType(lastRulePosition, ElementTypeRule.class)) {
          addParseProblem(element, "A '{' can only appear after an element type", rulePosition, false);
        }
      }
      else if (RulePosition.isRulePositionOfType(rulePosition, WOOGNLRule.class)) {
        boolean ognlIsValue = RulePosition.isOperatorOfType(lastRulePosition, AssignmentOperatorWordDetector.class);
        boolean ognlIsName = !ognlIsValue && (RulePosition.isOperatorOfType(lastRulePosition, EndAssignmentWordDetector.class) || RulePosition.isOperatorOfType(lastRulePosition, OpenDefinitionWordDetector.class));
        if (!ognlIsValue && !ognlIsName) {
          addParseProblem(element, "The OGNL value " + rulePosition._getTextWithoutException() + " can only appear after a '{', '=', or ';'.", rulePosition, false);
          savedRulePosition = null;
        }
        else if (ognlIsName) {
          savedRulePosition = rulePosition;
        }
        else if (ognlIsValue) {
          lastBinding = addBinding(element, savedRulePosition2, savedRulePosition, null, rulePosition, scanner);
          savedRulePosition = null;
          savedRulePosition2 = null;
          savedRulePosition3 = null;
        }
      }
      else if (RulePosition.isRulePositionOfType(rulePosition, StringLiteralRule.class)) {
        boolean literalIsValue = RulePosition.isOperatorOfType(lastRulePosition, AssignmentOperatorWordDetector.class);
        boolean literalIsName = !literalIsValue && (RulePosition.isOperatorOfType(rulePositions.peek(), EndAssignmentWordDetector.class) || RulePosition.isOperatorOfType(rulePositions.peek(), OpenDefinitionWordDetector.class));
        if (!literalIsValue && !literalIsName) {
          addParseProblem(element, "The string literal '" + rulePosition._getTextWithoutException() + "' can only appear after a '{', '=', or ';'.", rulePosition, false);
          savedRulePosition = null;
        }
        else if (literalIsName) {
          savedRulePosition = rulePosition;
        }
        else if (literalIsValue) {
          lastBinding = addBinding(element, savedRulePosition2, savedRulePosition, null, rulePosition, scanner);
          savedRulePosition = null;
          savedRulePosition2 = null;
          savedRulePosition3 = null;
        }
        tentativeElementName = null;
      }
      else if (RulePosition.isRulePositionOfType(rulePosition, BindingNameRule.class)) {
        if (!RulePosition.isOperatorOfType(lastRulePosition, OpenDefinitionWordDetector.class) && !RulePosition.isOperatorOfType(lastRulePosition, EndAssignmentWordDetector.class) && !RulePosition.isOperatorOfType(lastRulePosition, ElementTypeOperatorWordDetector.class)) {
          addParseProblem(element, "The binding name '" + rulePosition._getTextWithoutException() + "' can only appear after a '{' or a ';'", rulePosition, false);
        }
        savedRulePosition = rulePosition;
        lastBinding = null;
      }
      else if (RulePosition.isOperatorOfType(rulePosition, AssignmentOperatorWordDetector.class)) {
        if (!RulePosition.isRulePositionOfType(lastRulePosition, BindingNameRule.class) && !RulePosition.isRulePositionOfType(lastRulePosition, StringLiteralRule.class)) {
          addParseProblem(element, "An '=' can only appear after a binding name", rulePosition, false);
        }
      }
      else if (RulePosition.isRulePositionOfType(rulePosition, BindingValueNamespaceRule.class)) {
        if (!RulePosition.isOperatorOfType(lastRulePosition, AssignmentOperatorWordDetector.class)) {
          addParseProblem(element, "The binding value namespace '" + rulePosition._getTextWithoutException() + "' can only appear after an '='", rulePosition, false);
        }
        else {
          savedRulePosition3 = rulePosition;
        }
      }
      else if (RulePosition.isRulePositionOfType(rulePosition, BindingValueRule.class)) {
        if (!RulePosition.isOperatorOfType(lastRulePosition, AssignmentOperatorWordDetector.class) && !(RulePosition.isOperatorOfType(lastRulePosition, ElementTypeOperatorWordDetector.class) && RulePosition.isRulePositionOfType(savedRulePosition3, BindingValueNamespaceRule.class))) {
          addParseProblem(element, "The binding value '" + rulePosition._getTextWithoutException() + "' can only appear after an '=' or a 'xxx:'", rulePosition, false);
        }
        else {
          lastBinding = addBinding(element, savedRulePosition2, savedRulePosition, savedRulePosition3, rulePosition, scanner);
        }
        savedRulePosition = null;
        savedRulePosition2 = null;
        savedRulePosition3 = null;
      }
      else if (RulePosition.isOperatorOfType(rulePosition, EndAssignmentWordDetector.class)) {
        if (!RulePosition.isRulePositionOfType(lastRulePosition, BindingValueRule.class) && !RulePosition.isRulePositionOfType(lastRulePosition, StringLiteralRule.class) && !RulePosition.isRulePositionOfType(lastRulePosition, WOOGNLRule.class)) {
          addParseProblem(element, "A ';' can only appear after a binding value", rulePosition, false);
        }
      }
      else if (RulePosition.isOperatorOfType(rulePosition, CloseDefinitionWordDetector.class)) {
        if (element != null) {
          element.setEndOffset(rulePosition.getTokenOffset() + 1);
        }
        if (!RulePosition.isOperatorOfType(lastRulePosition, OpenDefinitionWordDetector.class) && !RulePosition.isOperatorOfType(lastRulePosition, EndAssignmentWordDetector.class) && !RulePosition.isRulePositionOfType(lastRulePosition, BindingValueRule.class) && !RulePosition.isRulePositionOfType(lastRulePosition, StringLiteralRule.class) && !RulePosition.isRulePositionOfType(lastRulePosition, WOOGNLRule.class)) {
          addParseProblem(element, "A '}' can only appear after a ';' or a '{'", rulePosition, false);
        }
        else {
          element = null;
        }
        lastBinding = null;
      }
      else {
        addParseProblem(element, "'" + rulePosition._getTextWithoutException() + "' is an unknown keyword", rulePosition, false);
      }

      if (!whitespace && !comment) {
        lastRulePosition = rulePosition;
        rulePositions.push(rulePosition);
      }
    }

    if (lastRulePosition != null && !RulePosition.isOperatorOfType(lastRulePosition, CloseDefinitionWordDetector.class)) {
      addParseProblem(element, "The last entry in a WOD file must be a '}'.", lastRulePosition, false);
    }
  }

  protected DocumentWodBinding addBinding(DocumentWodElement element, RulePosition namespaceRulePosition, RulePosition nameRulePosition, RulePosition valueNamespaceRulePosition, RulePosition valueRulePosition, WodScanner scanner) {
    DocumentWodBinding binding = null;
    if (element == null) {
      addParseProblem(element, "A binding must appear in a declaration", valueRulePosition, false);
    }
    else if (nameRulePosition == null) {
      addParseProblem(element, "A binding must have a name", valueRulePosition, false);
    }
    else if (valueRulePosition == null) {
      addParseProblem(element, "A binding must have a value", valueRulePosition, false);
    }
    else {
      binding = new DocumentWodBinding(namespaceRulePosition, nameRulePosition, valueNamespaceRulePosition, valueRulePosition);
      element.addBinding(binding);
    }
    return binding;
  }

  public String getName() {
    return _wodFile.getName();
  }

  public IFile getWodFile() {
    return _wodFile;
  }

  public int getStartOffset() {
    return 0;
  }

  public int getEndOffset() {
    return _document.getLength();
  }

  public IWodElement getWodElementAtIndex(int index) {
    IWodElement elementAtIndex = null;
    Iterator<IWodElement> elementsIter = getElements().iterator();
    while (elementAtIndex == null && elementsIter.hasNext()) {
      IWodElement element = elementsIter.next();
      if (isIndexContainedByWodUnit(index, element)) {
        elementAtIndex = element;
      }
    }
    return elementAtIndex;
  }

  public IWodUnit getWodUnitAtIndex(int index) {
    IWodUnit wodUnit = null;

    IWodElement elementAtIndex = getWodElementAtIndex(index);
    if (elementAtIndex != null) {
      Iterator<IWodBinding> bindingsIter = elementAtIndex.getBindings().iterator();
      while (wodUnit == null && bindingsIter.hasNext()) {
        IWodBinding binding = bindingsIter.next();
        if (isIndexContainedByWodUnit(index, binding)) {
          wodUnit = binding;
        }
      }
      if (wodUnit == null) {
        wodUnit = elementAtIndex;
      }
    }

    if (wodUnit == null) {
      wodUnit = this;
    }

    return wodUnit;
  }

  protected boolean isIndexContainedByWodUnit(int index, IWodUnit wodUnit) {
    return index >= wodUnit.getStartOffset() && index <= wodUnit.getEndOffset();
  }

  protected static class ForgivingStack<T> {
    private List<T> _contents;
   
    public ForgivingStack() {
      _contents = new LinkedList<T>();
    }
   
    public void push(T obj) {
      _contents.add(0, obj);
    }
   
    public void clear() {
      _contents.clear();
    }
   
    public T peek() {
      return peek(0);
    }
   
    public T peek(int offset) {
      T obj = null;
      if (_contents.size() > offset) {
        obj = _contents.get(offset);
      }
      return obj;
    }
  }
}
TOP

Related Classes of org.objectstyle.wolips.wodclipse.core.document.DocumentWodModel$ForgivingStack

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.