/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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.
*/
/*
* AdjunctSource.java
* Creation date: Jan 26, 2005.
* By: Joseph Wong
*/
package org.openquark.cal.compiler;
import java.io.Reader;
import java.io.StringReader;
import org.openquark.cal.compiler.SourceModel.TopLevelSourceElement;
/**
* Abstracts the source of a CAL adjunct. This abstraction allows the CAL
* compiler and typechecker to accept adjuncts in different representations
* (e.g. text and source model), and to process them accordingly.
*
* @author Joseph Wong
*/
public abstract class AdjunctSource {
/**
* Private constructor for AdjunctSource. This abstract class is not meant
* to be subclassed outside of this package.
*/
private AdjunctSource() {
}
/**
* Concatenates two adjuncts to form a combined adjunct containing all the
* elements from both.
*
* @param other
* the other piece of adjunct to be concatenated with this
* adjunct
* @return the concatenation of this adjunct and the specified adjunct
*/
abstract AdjunctSource concat(AdjunctSource other);
/**
* Converts the adjunct into its source text representation.
*
* @return the source text representation of this adjunct
*/
@Override
public abstract String toString();
/**
* Encapsulates the definition of an adjunct in source model form.
*
* @author Joseph Wong
*/
public static class FromSourceModel extends AdjunctSource {
/**
* The definition of the adjunct, as a list of
* <code>TopLevelSourceElement</code>s.
*/
private final SourceModel.TopLevelSourceElement[] elements;
/**
* Constructs an adjunct from a single source element.
*
* @param element
* the sole source element of the adjunct
*/
public FromSourceModel(SourceModel.TopLevelSourceElement element) {
SourceModel.verifyArg(element, "element");
this.elements = new SourceModel.TopLevelSourceElement[] { element };
}
/**
* Constructs an adjunct from an array of source elements.
*
* @param elements
* the source elements of the adjunct
*/
public FromSourceModel(SourceModel.TopLevelSourceElement[] elements) {
SourceModel.verifyArrayArg(elements, "elements");
this.elements = elements;
}
/**
* Concatenates two adjuncts to form a combined adjunct containing all
* the elements from both.
*
* @param other
* the other piece of adjunct to be concatenated with this
* adjunct
* @return the concatenation of this adjunct and the specified adjunct
*/
@Override
AdjunctSource concat(AdjunctSource other) {
SourceModel.verifyArg(other, "other");
if (other instanceof FromSourceModel) {
// create a new source-model-based adjunct with the source model
// elements from both this adjunct and the other adjunct
FromSourceModel smOther = (FromSourceModel)other;
int newLength = elements.length + smOther.elements.length;
SourceModel.TopLevelSourceElement[] newElements = new SourceModel.TopLevelSourceElement[newLength];
System.arraycopy(elements, 0, newElements, 0, elements.length);
System.arraycopy(smOther.elements, 0, newElements, elements.length, smOther.elements.length);
return new FromSourceModel(newElements);
} else if (other instanceof FromText) {
// since the other adjunct is text-based, create a new
// text-based adjunct with the combined source text
FromText textOther = (FromText)other;
StringBuilder sb = new StringBuilder();
for (final TopLevelSourceElement element : elements) {
sb.append(element.toSourceText()).append('\n');
}
sb.append(textOther.source);
return new FromText(sb.toString());
} else {
throw new UnsupportedOperationException(
"AdjunctSource.FromSourceModel.concat - argument type " + other.getClass() + "not supported.");
}
}
/**
* Converts the adjunct into its source text representation.
*
* @return the source text representation of this adjunct
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (final TopLevelSourceElement element : elements) {
element.toSourceText(sb);
sb.append('\n');
}
return sb.toString();
}
/**
* Converts the adjunct into the corresponding parse tree.
*
* @return the parse tree node for the adjunct
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode outerDefnListNode = new ParseTreeNode(
CALTreeParserTokenTypes.OUTER_DEFN_LIST, "OUTER_DEFN_LIST");
int numChildren = elements.length;
ParseTreeNode[] outerDefnNodes = new ParseTreeNode[numChildren];
for (int i = 0; i < numChildren; i++) {
outerDefnNodes[i] = elements[i].toParseTreeNode();
}
outerDefnListNode.addChildren(outerDefnNodes);
return outerDefnListNode;
}
/**
* @return the number of elements in this adjunct
*/
public int getNElements() {
return elements.length;
}
/**
* @param i
* the index for the desired element
* @return the <code>i</code>th element of this adjunct
*/
public SourceModel.TopLevelSourceElement getElement(int i) {
return elements[i];
}
}
/**
* Encapsulates the definition of an adjunct contained in text.
*
* @author Joseph Wong
*/
public static class FromText extends AdjunctSource {
/**
* The source text of the adjunct.
*/
private final String source;
/**
* Constructs an adjunct from its CAL source text.
*
* @param source
* the source of the adjunct
*/
public FromText(String source) {
SourceModel.verifyArg(source, "source");
this.source = source;
}
/**
* Concatenates two adjuncts to form a combined adjunct containing all
* the elements from both.
*
* @param other
* the other piece of adjunct to be concatenated with this
* adjunct
* @return the concatenation of this adjunct and the specified adjunct
*/
@Override
AdjunctSource concat(AdjunctSource other) {
SourceModel.verifyArg(other, "other");
if (other instanceof FromSourceModel) {
FromSourceModel smOther = (FromSourceModel)other;
StringBuilder sb = new StringBuilder(source).append('\n');
// since the other adjunct is in source model form, convert it to
// its CAL text representation for the combined text-based adjunct
for (final TopLevelSourceElement element : smOther.elements) {
sb.append(element.toSourceText()).append('\n');
}
return new FromText(sb.toString());
} else if (other instanceof FromText) {
FromText textOther = (FromText)other;
StringBuilder sb = new StringBuilder(source).append('\n');
sb.append(textOther.source);
return new FromText(sb.toString());
} else {
throw new UnsupportedOperationException(
"AdjunctSource.FromSourceModel.concat - argument type " + other.getClass() + "not supported.");
}
}
/**
* Converts the adjunct into its source text representation.
*
* @return the source text representation of this adjunct
*/
@Override
public String toString() {
return source;
}
/**
* Obtains a new Reader for the source text.
*
* @return the reader
*/
Reader getReader() {
return new StringReader(source);
}
}
}