/*
* Name: BasicTemplateParser
* Authors: Richard Rodger
*
* Copyright (c) 2000-2005 Richard Rodger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
// package
package org.jostraca;
// import
import org.jostraca.section.Section;
import org.jostraca.section.SectionSet;
import org.jostraca.unit.UnitList;
import org.jostraca.unit.BasicUnitProcessor;
//import org.jostraca.unit.DebugUnitProcessor;
import org.jostraca.util.Standard;
import org.jostraca.util.StandardException;
import org.jostraca.util.PropertySet;
import org.jostraca.util.Internal;
import org.jostraca.util.ErrorUtil;
import org.jostraca.util.TextUtil;
import org.jostraca.comp.antlr.TokenStreamRecognitionException;
import org.jostraca.comp.antlr.RecognitionException;
import java.io.StringReader;
/** Basic implementation of TemplateParser.
*/
public class BasicTemplateParser implements TemplateParser, TemplateActionHandler {
// public static
public static final String CN = BasicTemplateParser.class.getName();
// private instance
private String iSourceText = new String(); // template source
private SectionSet iSectionSet = new SectionSet(); // sections found
private PropertySet iPropertySet = new PropertySet(); // properties used
private int iLastElementType = TemplateElementProcessor.ELEMENT_TYPE_none;
// protected instance
protected String iDefaultSectionName = Section.NAME_body;
protected char iOpenOuterChar = Standard.LESSTHAN.charAt(0);
protected char iOpenInnerChar = Standard.PERCENT.charAt(0);
protected char iCloseInnerChar = Standard.PERCENT.charAt(0);
protected char iCloseOuterChar = Standard.GREATERTHAN.charAt(0);
// constructors
/** No Args Constructor. */
public BasicTemplateParser() {
// does nothing
}
// interface TemplateActionHandler
public void setDefaultSection( String pSectionName ) {
if( ErrorUtil.not_null( pSectionName, "pSectionName" ) ) {
if( 0 == pSectionName.length() ) {
iDefaultSectionName = Section.NAME_body;
}
else {
iDefaultSectionName = pSectionName;
}
}
}
public String getDefaultSection() {
return iDefaultSectionName;
}
public Section getSection( String pSectionName ) {
return iSectionSet.getSection( pSectionName );
}
public void append( String pSectionName, String pContent ) {
// check for nulls
if( ErrorUtil.is_null( pSectionName, "pSectionName" ) ) {
return;
}
if( ErrorUtil.is_null( pContent, "pContent" ) ) {
return;
}
iSectionSet.appendToSection( pSectionName, pContent );
}
public void append( String pContent ) {
if( ErrorUtil.not_null( pContent, "pContent" ) ) {
iSectionSet.appendToSection( iDefaultSectionName, pContent );
}
}
// public methods
/** Append text to a given section.
* @param pSectionName Name of section to append text to.
* @param pContent Text to append to section.
*/
public void appendToSection( String pSectionName, String pContent ) {
// check for nulls
if( ErrorUtil.is_null( pSectionName, "pSectionName" ) ) {
return;
}
if( ErrorUtil.is_null( pSectionName, "pSectionName" ) ) {
return;
}
iSectionSet.appendToSection( pSectionName, pContent );
}
/** @see TemplateActionHandler#getLastElementType */
public int getLastElementType() {
return iLastElementType;
}
/** @see TemplateActionHandler#getLastElementType */
public void setLastElementType( int pLastElementType ) {
iLastElementType = pLastElementType;
}
/** Set text to be parsed.
* @param pSourceText Text to be parsed
*/
public void setSourceText( String pSourceText ) throws TemplateParserException {
iSourceText = Internal.null_arg( pSourceText );
}
/** Set SectionSet to be used in parse.
* @param pSectionSet SectionSet used in parse.
* @exception TemplateParserException Thrown if pSourceText is null
*/
public void setSectionSet( SectionSet pSectionSet ) throws TemplateParserException {
iSectionSet = (SectionSet) Internal.null_arg( pSectionSet );
}
/** Set PropertySet to be used in parse.
* @param pPropertySet PropertySet used in parse.
* @exception TemplateParserException Thrown if pSourceText is null
*/
public void setPropertySet( PropertySet pPropertySet ) throws TemplateParserException {
iPropertySet = (PropertySet) Internal.null_arg( pPropertySet );
// get code writer settings from PropertySet
String openOuterChar = parseParseCharValue( Property.parse_OpenOuterChar, iPropertySet );
String openInnerChar = parseParseCharValue( Property.parse_OpenInnerChar, iPropertySet );
String closeInnerChar = parseParseCharValue( Property.parse_CloseInnerChar, iPropertySet );
String closeOuterChar = parseParseCharValue( Property.parse_CloseOuterChar, iPropertySet );
if( 0 < openOuterChar.length() ) { setOpenOuterChar( openOuterChar.charAt(0) ); }
if( 0 < openInnerChar.length() ) { setOpenInnerChar( openInnerChar.charAt(0) ); }
if( 0 < closeInnerChar.length() ) { setCloseInnerChar( closeInnerChar.charAt(0) ); }
if( 0 < closeOuterChar.length() ) { setCloseOuterChar( closeOuterChar.charAt(0) ); }
}
/** Parse text and update SectionSet. Errors will return via UserErrorStore when implemented :). */
public void parse() {
Service.t.track( "parse", "start" );
String currentContent = null;
try {
initSectionSet();
TemplateElementProcessor tep = new BasicTemplateElementProcessor( this, iPropertySet );
currentContent = iSourceText;
// init lexer
BasicTemplateAntlrLexer lexer = new BasicTemplateAntlrLexer( new StringReader( iSourceText ) );
lexer.setOpenOuterChar( iOpenOuterChar );
lexer.setOpenInnerChar( iOpenInnerChar );
lexer.setCloseInnerChar( iCloseInnerChar );
lexer.setCloseOuterChar( iCloseOuterChar );
// do parse
BasicTemplateAntlrParser parser = new BasicTemplateAntlrParser( lexer );
parser.template();
// handle blocks
String processedText = null;
String section = null;
BlockList blockList = parser.getBlockList();
BlockList extraBlocks = null;
Block block = null;
boolean finished = false;
while( blockList.hasMoreBlocks() ) {
block = blockList.nextBlock();
finished = tep.process( block );
// REVIEW: clean this up
if( !finished ) {
currentContent = tep.getContent();
lexer = new BasicTemplateAntlrLexer( new StringReader( currentContent ) );
lexer.setOpenOuterChar( iOpenOuterChar );
lexer.setOpenInnerChar( iOpenInnerChar );
lexer.setCloseInnerChar( iCloseInnerChar );
lexer.setCloseOuterChar( iCloseOuterChar );
parser = new BasicTemplateAntlrParser( lexer );
parser.template();
extraBlocks = parser.getBlockList();
// check for infinite recursion
if( 1 == extraBlocks.numBlocks() && block.equals( extraBlocks.getBlock(0) ) ) {
ErrorUtil.nonFatalMsg( CN+": infinite loop caught in Block processing on Block:["+block+"]" );
}
else {
blockList.insert( extraBlocks );
}
}
}
// REVIEW: X option to use old parser
UnitList ul = tep.getUnitList();
//DebugUnitProcessor dup = new DebugUnitProcessor();
//SectionSet dss = dup.process( ul );
//System.out.println( dss );
BasicUnitProcessor bup = new BasicUnitProcessor();
bup.setPropertySet( iPropertySet );
SectionSet uss = bup.process( ul );
//System.out.println( "uss:"+uss );
//System.out.println( "iSectionSet:"+iSectionSet );
//System.out.println( "uss==iSectionSet:"+uss.equals(iSectionSet) );
if( ! iPropertySet.isYes( Property.jostraca_old ) ) {
iSectionSet = uss;
}
else {
// leave old iSectionSet in place
}
Service.t.track( "parse", "end" );
}
catch( StandardException se ) {
throw se;
}
catch( TokenStreamRecognitionException tsre ) {
RecognitionException re = tsre.recog;
if( null != re ) {
int lineNumber = re.getLine();
String line = TextUtil.getLine( currentContent, lineNumber-1 );
if( Standard.EMPTY == line ) {
throw new TemplateParserException( TemplateParserException.CODE_syntax_error, re.getMessage() );
}
else {
throw new TemplateParserException( TemplateParserException.CODE_syntax_error, line );
}
}
else {
throw new TemplateParserException( tsre );
}
}
catch( Exception e ) {
throw new TemplateParserException( e );
}
}
/** Get SectionSet built from parse. */
public SectionSet getSectionSet() {
return iSectionSet;
}
public void setOpenOuterChar( char pOpenOuterChar ) { iOpenOuterChar = pOpenOuterChar; }
public void setOpenInnerChar( char pOpenInnerChar ) { iOpenInnerChar = pOpenInnerChar; }
public void setCloseInnerChar( char pCloseInnerChar ) { iCloseInnerChar = pCloseInnerChar; }
public void setCloseOuterChar( char pCloseOuterChar ) { iCloseOuterChar = pCloseOuterChar; }
// private methods
/** Clear writer format sections. */
private void initSectionSet() {
iSectionSet.clearAllSections();
}
// FIX: make '\\' configurable
private String parseParseCharValue( String pParseCharName, PropertySet pPropertySet ) {
String parseChar = pPropertySet.get( pParseCharName );
parseChar = parseChar.replace('\\',' ').trim();
if( 1 < parseChar.length() ) {
throw new TemplateParserException( TemplateParserException.CODE_invalid_parse_char,
new String[] { "parse-char", parseChar, "parse-char-name", pParseCharName } );
}
return parseChar;
}
}