Package dtool.sourcegen

Source Code of dtool.sourcegen.TemplatedSourceProcessor$TemplatedSourceProcessingException

/*******************************************************************************
* Copyright (c) 2012, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Bruno Medeiros - initial API and implementation
*******************************************************************************/
package dtool.sourcegen;

import static dtool.sourcegen.TemplatedSourceProcessor.StandardErrors.MISMATCHED_VARIATION_SIZE;
import static dtool.sourcegen.TemplatedSourceProcessor.StandardErrors.UNDEFINED_REFER;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertFail;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import melnorme.utilbox.iteration.ChainedIterator2;
import melnorme.utilbox.iteration.CopyableListIterator;
import melnorme.utilbox.iteration.ICopyableIterator;
import melnorme.utilbox.misc.ArrayUtil;
import dtool.sourcegen.AnnotatedSource.MetadataEntry;
import dtool.sourcegen.TemplatedSourceProcessorParser.Argument;
import dtool.sourcegen.TemplatedSourceProcessorParser.TemplatedSourceException;
import dtool.sourcegen.TemplatedSourceProcessorParser.TspCommandElement;
import dtool.sourcegen.TemplatedSourceProcessorParser.TspElement;
import dtool.sourcegen.TemplatedSourceProcessorParser.TspExpansionElement;
import dtool.sourcegen.TemplatedSourceProcessorParser.TspIfElseExpansionElement;
import dtool.sourcegen.TemplatedSourceProcessorParser.TspMetadataElement;
import dtool.sourcegen.TemplatedSourceProcessorParser.TspStringElement;
import dtool.util.NewUtils;

/**
* Generates multiple source cases from a templated source, using an embedded markup language.
*/
public class TemplatedSourceProcessor extends SplitProcessor {
 
  public static AnnotatedSource[] processTemplatedSource(String marker, String source)
    throws TemplatedSourceException {
    TemplatedSourceProcessor tsp = new TemplatedSourceProcessor();
    return tsp.processSource(marker, source);
  }
 
  protected final Map<String, TspExpansionElement> globalExpansions = new HashMap<>();
  protected final ArrayList<AnnotatedSource> genCases = new ArrayList<>();
  protected final TemplatedSourceProcessorParser tspParser = new TemplatedSourceProcessorParser() {
    @Override
    protected void handleParserError(TemplatedSourceException tse) throws TemplatedSourceException {
      handleError(tse);
    };
  };
 
  public TemplatedSourceProcessor() { }
 
  public Map<String, TspExpansionElement> getGlobalExpansions() {
    return globalExpansions;
  }
 
  public void addGlobalExpansions(Map<String, TspExpansionElement> newGlobalExpansions) {
    NewUtils.addNew(globalExpansions, newGlobalExpansions);
  }
 
  public ArrayList<AnnotatedSource> getGenCases() {
    return genCases;
  }
 
  public AnnotatedSource[] processSource(String defaultMarker, String fileSource)
    throws TemplatedSourceException {
    splitSourceCases(defaultMarker, fileSource);
    return ArrayUtil.createFrom(getGenCases(), AnnotatedSource.class);
  }
 
  public AnnotatedSource[] processSource_unchecked(String defaultMarker, String unprocessedSource) {
    try {
      return processSource(defaultMarker, unprocessedSource);
    } catch(TemplatedSourceException e) {
      throw melnorme.utilbox.core.ExceptionAdapter.unchecked(e);
    }
  }
 
  protected void checkError(boolean errorCondition, ProcessingState sourceCase) throws TemplatedSourceException {
    if(errorCondition) {
      reportError(sourceCase);
    }
  }
 
  protected void reportError(ProcessingState sourceCase) throws TemplatedSourceException {
    tspParser.reportError(sourceCase.sourceSB.length());
  }
 
  protected void checkError(boolean errorCondition, StandardErrors errorType, TspExpansionElement expansion)
    throws TemplatedSourceException {
    if(errorCondition) {
      String str = expansion.expansionId != null ? expansion.expansionId : "";
      str += expansion.pairedExpansionId != null ? ":"+expansion.pairedExpansionId : "";
      handleError(new TemplatedSourceProcessingException(-1, errorType, str));
    }
  }
 
  public static enum StandardErrors {
    REDEFINITION,
    UNDEFINED_REFER,
    NO_ARGUMENTS,
    MISMATCHED_VARIATION_SIZE,
  }
 
  @SuppressWarnings("serial")
  public static class TemplatedSourceProcessingException extends TemplatedSourceException {
    public final StandardErrors errorString;
    public final Object errorObject;
   
    public TemplatedSourceProcessingException(int errorOffset, StandardErrors errorString, Object errorObject) {
      super(errorOffset);
      this.errorString = errorString;
      this.errorObject = errorObject;
    }
  }
 
  // --------------------- Generation phase ---------------------

  @Override
  protected void processSplitCaseSource(String caseSource, boolean isHeader, String keyMarker)
    throws TemplatedSourceException {
    ArrayList<TspElement> sourceElements = tspParser.parseSplitCase(caseSource, keyMarker);
    ProcessingState processingState = new ProcessingState(isHeader, caseSource);
    processCaseContents(processingState, new CopyableListIterator<TspElement>(sourceElements));
  }
 
 
 
  public class ProcessingState {
   
    public final boolean isHeaderCase;
    public final String originalSource;
    protected StringBuilder sourceSB = new StringBuilder();
    protected TemporaryMetadataEntry topLevelMDE = null;
    public final ArrayList<MetadataEntry> metadata = new ArrayList<MetadataEntry>();
    public final Map<String, TspExpansionElement> expansionDefinitions =
      new HashMap<String, TspExpansionElement>();
    public final Map<String, Integer> activeExpansions = new HashMap<String, Integer>();
   
    public ProcessingState(boolean isHeaderCase, String originalSource) {
      this.isHeaderCase = isHeaderCase;
      this.originalSource = originalSource;
    }
   
    public ProcessingState(boolean isHeaderCase, String originalSrc, StringBuilder sourceSB,
      TemporaryMetadataEntry topLevelMDE, List<MetadataEntry> metadata, Map<String, Integer> activeExpansions,
      Map<String, TspExpansionElement> expansionDefinitions) {
      this.isHeaderCase = isHeaderCase;
      this.originalSource = originalSrc;
      this.sourceSB.append(sourceSB.toString());
      this.topLevelMDE = topLevelMDE;
      this.metadata.addAll(metadata);
      this.activeExpansions.putAll(activeExpansions);
      this.expansionDefinitions.putAll(expansionDefinitions);
    }
   
    @Override
    public ProcessingState clone() {
      return new ProcessingState(isHeaderCase, originalSource, sourceSB, topLevelMDE, metadata,
        activeExpansions, expansionDefinitions);
    }
   
    public TspExpansionElement getExpansion(String expansionId) {
      if(!isHeaderCase) {
        TspExpansionElement expansionElement = expansionDefinitions.get(expansionId);
        if(expansionElement != null) {
          return expansionElement;
        }
      }
      return globalExpansions.get(expansionId);
    }
   
    public void putExpansion(String expansionId, TspExpansionElement expansionElement) {
      if(!isHeaderCase) {
        expansionDefinitions.put(expansionId, expansionElement);
      } else {
        globalExpansions.put(expansionId, expansionElement);
      }
    }
  }
 
  protected void processCaseContents(ProcessingState sourceCase, ICopyableIterator<TspElement> elementStream)
    throws TemplatedSourceException {
    assertNotNull(sourceCase);
   
    while(elementStream.hasNext()) {
      TspElement tspElem = elementStream.next();
      elementStream = elementStream.optimizedSelf();
     
      if(tspElem instanceof TspExpansionElement) {
        TspExpansionElement expansionElem = (TspExpansionElement) tspElem;
       
        boolean endProcessing = processExpansionElement(sourceCase, elementStream, expansionElem);
        if(endProcessing) {
          return;
        }
      } else if(tspElem instanceof TspStringElement) {
        TspStringElement stringElem = (TspStringElement) tspElem;
        sourceCase.sourceSB.append(stringElem.producedText);
      } else if(tspElem instanceof TspMetadataElement) {
        final TspMetadataElement mdElem = (TspMetadataElement) tspElem;
        elementStream = processMetadataElement(sourceCase, elementStream, mdElem);
      } else if(tspElem instanceof TspIfElseExpansionElement) {
        TspIfElseExpansionElement tspIfElse = (TspIfElseExpansionElement) tspElem;
        elementStream = processIfElseExpansion(sourceCase, elementStream, tspIfElse);
      } else if(tspElem instanceof TspMetadataEndElement) {
        processMetadataEndElem(sourceCase, (TspMetadataEndElement) tspElem);
      } else if(tspElem instanceof TspCommandElement) {
        TspCommandElement tspCommandElement = (TspCommandElement) tspElem;
        assertTrue(tspCommandElement.name.equals(TspCommandElement.DISCARD_CASE));
        return;
      } else {
        assertFail();
      }
    }
   
    addFullyProcessedSourceCase(sourceCase);
  }
 
  protected void addFullyProcessedSourceCase(ProcessingState caseState) {
    if(caseState.isHeaderCase == false) {
      String source = caseState.sourceSB.toString();
      genCases.add(new AnnotatedSource(source, caseState.originalSource, caseState.metadata));
    }
  }
 
  public ICopyableIterator<TspElement> processMetadataElement(ProcessingState sourceCase,
    ICopyableIterator<TspElement> elementStream, final TspMetadataElement mdElem) {
    int metadataIx = sourceCase.metadata.size();
    TemporaryMetadataEntry temporaryParentMDE = new TemporaryMetadataEntry(mdElem);
    sourceCase.metadata.add(temporaryParentMDE);
    final TspMetadataEndElement mdEndElem = new TspMetadataEndElement(mdElem, sourceCase, metadataIx);
   
    if(mdElem.childElements != null) {
      Argument sourceArgument = mdElem.childElements;
     
      if(mdElem.outputSource == false) {
        sourceCase.sourceSB = new StringBuilder(); // Create a temporary source output
        sourceCase.topLevelMDE = temporaryParentMDE;
      }
     
      ICopyableIterator<TspElement> mdArgIter = ChainedIterator2.create(
        CopyableListIterator.create(sourceArgument),
        CopyableListIterator.create(Collections.<TspElement>singletonList(mdEndElem))
      );
      elementStream = ChainedIterator2.create(mdArgIter, elementStream);
    } else {
      processMetadataEndElem(sourceCase, mdEndElem);
    }
    return elementStream;
  }
 
  protected class TemporaryMetadataEntry extends MetadataEntry {
    public TemporaryMetadataEntry(TspMetadataElement mdElem) {
      super(mdElem.tag, mdElem.value, null, 0, null, false);
    }
  }
 
  protected static class TspMetadataEndElement extends TspElement {
    public final TspMetadataElement mdElem;
    public final int offset;
    public final int metadataIx;
    private final StringBuilder originalSB;
    public final TemporaryMetadataEntry originalTopLevelMDE;
    public final ProcessingState originalSourceCase;
   
    public TspMetadataEndElement(TspMetadataElement mdElem, ProcessingState sourceCase,  int metadataIx) {
      this.mdElem = mdElem;
      this.offset = sourceCase.sourceSB.length();
      this.metadataIx = metadataIx;
      this.originalSourceCase = sourceCase;
      this.originalSB = sourceCase.sourceSB;
      if(mdElem.childElements != null && mdElem.outputSource == false) {
        this.originalTopLevelMDE = sourceCase.topLevelMDE;
      } else {
        this.originalTopLevelMDE = null;
      }
    }
   
    public StringBuilder getOriginalSB(ProcessingState sourceCase) {
      if(originalSourceCase == sourceCase) {
        return originalSB;
      } else {
        return new StringBuilder(originalSB); // An expansion has occurred so we need to duplicate
      }
    }
   
    @Override
    public String toString() {
      return "<MD-END:"+offset+">";
    }
  }
 
  public void processMetadataEndElem(ProcessingState sourceCase, TspMetadataEndElement mdEndElem) {
    int offset = mdEndElem.offset;
    String associatedSource = null;
   
    TspMetadataElement mdElem = mdEndElem.mdElem;
    if(mdElem.childElements != null) {
      if(mdElem.outputSource) {
        associatedSource = sourceCase.sourceSB.substring(offset, sourceCase.sourceSB.length());
      } else {
        associatedSource = sourceCase.sourceSB.toString();
        sourceCase.sourceSB = mdEndElem.getOriginalSB(sourceCase); // Restore original source output
        sourceCase.topLevelMDE = mdEndElem.originalTopLevelMDE;
      }
    }
    boolean sourceWasIncluded = mdElem.outputSource;
   
    MetadataEntry mde = new MetadataEntry(mdElem.tag, mdElem.value, associatedSource, offset,
      sourceCase.topLevelMDE, sourceWasIncluded);
    assertTrue(sourceCase.metadata.get(mdEndElem.metadataIx) instanceof TemporaryMetadataEntry);
    sourceCase.metadata.set(mdEndElem.metadataIx, mde);
  }
 
  protected boolean processExpansionElement(ProcessingState sourceCase, ICopyableIterator<TspElement> elementStream,
    TspExpansionElement expansionElem) throws TemplatedSourceException {
   
    final String expansionId = expansionElem.expansionId;
    checkError(sourceCase.isHeaderCase && expansionId == null, sourceCase);
   
    checkError(expansionElem.anonymousExpansion && expansionElem.dontOuputSource, sourceCase);
    checkError(expansionElem.expansionId == null && expansionElem.dontOuputSource, sourceCase);
    checkError(expansionElem.expansionId == null && expansionElem.arguments == null, sourceCase);
   
    ArrayList<Argument> arguments = expansionElem.arguments;
    TspExpansionElement definedExpansionElem = null;
    if(expansionId != null) {
      definedExpansionElem = sourceCase.getExpansion(expansionId);
     
      if(arguments == null) {
        checkError(definedExpansionElem == null, UNDEFINED_REFER, expansionElem);
        arguments = definedExpansionElem.arguments;
      } else {
        // We allow a "redefinition" only if the element is exactly the same
        checkError(definedExpansionElem != null && definedExpansionElem != expansionElem,
          StandardErrors.REDEFINITION, expansionElem);
        putExpansion(sourceCase, expansionId, expansionElem);
      }
    }
    checkError(arguments.size() == 0, StandardErrors.NO_ARGUMENTS, expansionElem);
   
    if(expansionElem.defineOnly || sourceCase.isHeaderCase) {
      // TODO:  situation where there is a pairedExpansionId has no test cases that test it
      return false;
    }
   
    String secondaryIdToActivate = expansionElem.anonymousExpansion ? null : expansionId;
    String pairedIdToActivate = null;
   
    Integer pairedExpansionIx = null;
    TspExpansionElement referredExpansion = null;
    if(expansionElem.pairedExpansionId == null) {
      if(definedExpansionElem != null && expansionElem.anonymousExpansion == false) {
        pairedIdToActivate = definedExpansionElem.pairedExpansionId;
        if(pairedIdToActivate == null) {
          pairedIdToActivate = expansionId;
        }
      }
    } else {
      // Paired expansion referral.
     
      referredExpansion = sourceCase.getExpansion(expansionElem.pairedExpansionId);
      if(expansionElem.anonymousExpansion) {
      } else {
         // If referred, then it must be defined
        checkError(referredExpansion == null, UNDEFINED_REFER, expansionElem);
        checkError(arguments.size() != referredExpansion.arguments.size(),
          MISMATCHED_VARIATION_SIZE, expansionElem);
      }
      pairedIdToActivate = expansionElem.pairedExpansionId;
    }
   
    if(pairedIdToActivate != null) {
      pairedExpansionIx = sourceCase.activeExpansions.get(pairedIdToActivate);
    }
   
    if(pairedExpansionIx != null) {
      if(sourceCase.activeExpansions.get(secondaryIdToActivate) != null) {
        secondaryIdToActivate = null;
      }
      pairedIdToActivate = null;
      int ix = pairedExpansionIx;
      processArgument(sourceCase, elementStream, secondaryIdToActivate, null, arguments.get(ix), ix);
    } else {
      for (int ix = 0; ix < arguments.size(); ix++) {
        processArgument(sourceCase, elementStream, secondaryIdToActivate, pairedIdToActivate,
          arguments.get(ix), ix);
      }
    }
    return true;
  }
 
  protected void putExpansion(ProcessingState sourceCase, final String expansionId,
    TspExpansionElement expansionElem) {
    sourceCase.putExpansion(expansionId, expansionElem);
  }
 
  protected void processArgument(ProcessingState sourceCase, ICopyableIterator<TspElement> elementStream,
    String expansionId, String pairingId, Argument argument, int index) throws TemplatedSourceException {
    ProcessingState newState = sourceCase.clone();
    activateId(newState, expansionId, index);
    activateId(newState, pairingId, index);
   
    ICopyableIterator<TspElement> newElements = (argument == null) ?
      elementStream.copyState() :
      ChainedIterator2.create(CopyableListIterator.create(argument), elementStream.copyState())
      ;
    processCaseContents(newState, newElements);
  }
 
  public void activateId(ProcessingState newState, String expansionId, int index) {
    if(expansionId != null) {
      Integer oldValue = newState.activeExpansions.put(expansionId, index);
      assertTrue(oldValue == null || oldValue == index);
    }
  }
 
  public ICopyableIterator<TspElement> processIfElseExpansion(ProcessingState sourceCase,
    ICopyableIterator<TspElement> elementStream, TspIfElseExpansionElement tspIfElse) {
    Argument sourceArgument = tspIfElse.invert ? tspIfElse.argThen : tspIfElse.argElse;
   
    for (MetadataEntry mde : sourceCase.metadata) {
      if(mde != null && mde.name.equals(tspIfElse.mdConditionId)) {
        sourceArgument = tspIfElse.invert ? tspIfElse.argElse : tspIfElse.argThen;
        break;
      }
    }
    if(sourceArgument != null) {
      ICopyableIterator<TspElement> mdArgIter = CopyableListIterator.create(sourceArgument);
      elementStream = ChainedIterator2.create(mdArgIter, elementStream);
    }
    return elementStream;
  }
 
}
TOP

Related Classes of dtool.sourcegen.TemplatedSourceProcessor$TemplatedSourceProcessingException

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.