/*
* 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.
*/
/*
* CALMultiplexedLexer.java
* Creation date: Jul 19, 2005.
* By: Joseph Wong
*/
package org.openquark.cal.compiler;
import java.io.Reader;
import java.util.Collection;
import antlr.CharScanner;
import antlr.RecognitionException;
import antlr.Token;
import antlr.TokenStream;
import antlr.TokenStreamException;
import antlr.TokenStreamSelector;
/**
* Warning- this class should only be used by the CAL compiler implementation. It is not part of the
* external API of the CAL platform.
* <p>
* Instances of this class encapsulates the multiplexing of the two lexers used in lexing
* CAL source: the main CAL lexer and the CALDoc lexer. Since these two lexers are codependent
* (namely on scanning '/''*''*' as the start of a CALDoc comment, and '*''/' as the end of one),
* the two lexers should not be created or accessed individually, but rather through an instance
* of this class, which guarantees that they are always created and used as a pair.
*
* @author Joseph Wong
*/
public class CALMultiplexedLexer implements TokenStream {
/** The number of spaces represented by a tab character '\t'. **/
public static final int TAB_SIZE = 4;
/**
* The compiler instance that owns this multiplexed lexer, or null if this
* lexer is used in a standalone fashion.
*/
private final CALCompiler compiler;
/**
* collection to which filtered tokens are added
* this may be null, in which case filtered tokens are discarded
*/
private final Collection<SourceEmbellishment> embellishments;
/** The main lexer for the CAL grammar. */
private final CALLexer lexer;
/** The lexer for the CALDoc grammar. */
private final CALDocLexer caldocLexer;
/** The stream selector for switching between the main lexer and the CALDoc lexer. */
private final TokenStreamSelector streamSelector;
/**
* Construct a CALMultiplexedLexer hooked up to a java.io.Reader.
*
* @param compiler
* the CALCompiler that owns this multiplexed lexer, or null if
* this lexer is standalone.
* @param reader
* the Reader to be scanned by this multiplexed lexer.
* @param embellishments
* a collection that is used to store filtered tokens
* if this is null the tokens will be discarded, otherwise
* they will be added to the collection
*/
public CALMultiplexedLexer(CALCompiler compiler, Reader reader,
Collection<SourceEmbellishment> embellishments) {
this.compiler = compiler;
// Make a main lexer and a CALDoc lexer
lexer = new CALLexer(this, reader);
caldocLexer = new CALDocLexer(this, lexer.getInputState());
// Create a lexical selector and add the two lexers
streamSelector = new TokenStreamSelector();
streamSelector.addInputStream(lexer, "main");
streamSelector.addInputStream(caldocLexer, "caldoclexer");
// Set the starting token stream
streamSelector.select(lexer);
this.embellishments = embellishments;
}
/**
* This filters out the comment tokens and buffers them
* @return the next token from the currently selected lexer.
*/
public Token nextToken() throws TokenStreamException {
Token next;
while ((next = streamSelector.nextToken()) != null &&
SourceEmbellishment.isEmbellishmentToken(next)) {
if (embellishments != null) {
SourceEmbellishment emellishment = SourceEmbellishment.make(next);
if (emellishment != null) {
embellishments.add(emellishment);
}
}
}
return next;
}
/**
* Set the name of the file currently being scanned into the two constituent
* lexers.
*
* @param filename
* the name of the file being scanned.
*/
public void setFilename(String filename) {
lexer.setFilename(filename);
caldocLexer.setFilename(filename);
}
/**
* @return the tab size used by the two constituent lexers.
*/
public int getTabSize() {
return lexer.getTabSize();
}
public Token getTokenObject() {
return ((CharScanner) streamSelector.getCurrentStream()).getTokenObject();
}
/**
* Switch the parser to use the CALDoc lexer.
*/
void switchToCALDocLexer() {
caldocLexer.resetState();
streamSelector.select(caldocLexer);
}
/**
* Switch the parser back to using the CAL main lexer.
*/
void switchOutOfCALDocLexer() {
streamSelector.select(lexer);
}
/**
* Provides a reportError implementation to the two lexers so as to direct
* standard error handling through to the CALCompiler error scheme.
*
* @param ex
* RecognitionException the recognition exception that originated
* the problem
*/
void reportError(RecognitionException ex) {
if (compiler != null) {
final SourceRange sourceRange = CALParser.makeSourceRangeFromException(
ex);
compiler.logMessage(new CompilerMessage(sourceRange,
new MessageKind.Error.SyntaxError(),
ex));
}
}
}