/* * EuroCarbDB, a framework for carbohydrate bioinformatics * * Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * A copy of this license accompanies this distribution in the file LICENSE.txt. * * 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 Lesser General Public License * for more details. * * Last commit: $Rev: 1499 $ by $Author: glycoslave $ on $Date:: 2009-07-14 #$ */ package org.eurocarbdb.sugar.seq.grammar; // stdlib imports import java.util.List; import java.util.ArrayList; import java.util.Arrays; // 3rd party imports import org.apache.log4j.Logger; import antlr.Token; import antlr.SemanticException; // eurocarb imports import org.eurocarbdb.sugar.Residue; import org.eurocarbdb.sugar.Substituent; import org.eurocarbdb.sugar.Monosaccharide; import org.eurocarbdb.sugar.SequenceFormatException; import org.eurocarbdb.sugar.Anomer; import org.eurocarbdb.sugar.Basetype; import org.eurocarbdb.sugar.Superclass; import org.eurocarbdb.sugar.RingConformation; import org.eurocarbdb.sugar.SugarException; import org.eurocarbdb.sugar.CommonSubstituent; import org.eurocarbdb.sugar.impl.SimpleMonosaccharide; // static imports import static org.eurocarbdb.sugar.Basetypes.getNormalisedBasetype; import static org.eurocarbdb.util.StringUtils.join; import static org.eurocarbdb.sugar.CommonSubstituent.Deoxy; import static org.eurocarbdb.sugar.CommonSubstituent.En; /* class MonosacResidueToken *//************************************** * * Sub-class of {@link ResidueToken} to encapsulate information about * a parsed {@link Monosaccharide}. * * @author mjh */ public class MonosacResidueToken extends ResidueToken { //~~~~~~~~~~~~~~~~~~~~~ STATIC FIELDS ~~~~~~~~~~~~~~~~~~~~~~~// /** Logging instance. */ public static final Logger log = Logger.getLogger( MonosacResidueToken.class ); //~~~~~~~~~~~~~~~~~~~~~~~~~~ FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~~~~// protected Anomer anomer; protected Basetype basetype; protected Superclass superclass; protected RingConformation conformation; protected List<Substituent> substituents = null; protected int ringStart = -1; protected int ringEnd = -1; //~~~~~~~~~~~~~~~~~~~~~~~~ CONSTRUCTORS ~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Constructor. * * @param parser The parser generating this token * @param tok The ANTLR token being wrapped. * @param r A pre-constructed {@link Residue} */ public MonosacResidueToken( ParserAdaptor parser, Token tok, Residue r ) { super( parser, tok, r ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~ METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /* getResidue *//********************************************** * * Always returns a {@link Monosaccharide}. */ public Residue getResidue() throws SequenceFormatException { if ( residue != null ) return residue; assert basetype != null; if ( substituents != null ) { if ( log.isDebugEnabled() ) { log.debug( "normalising basetype " + basetype + " against substituents: " + substituents ); } try { // hack for glycoct residues like 'Ara-HEX|2-keto', where C1 // could be taken for either a (second) Carbonyl or a hydroxl if ( basetype.getSuperclass() != this.superclass && substituents.contains( CommonSubstituent.Carbonyl ) && substituents.get(0) == null ) { // hint to the normalise routine that the basetypes // like the example above should be normalised to // 'Fru'. substituents.set( 0, CommonSubstituent.OH ); } basetype = getNormalisedBasetype( basetype, substituents ); } catch ( Exception ex ) { SequenceFormatException sfex = parser.createSyntaxException( this.token, ex.getMessage() ); sfex.initCause( ex ); throw sfex; } } Monosaccharide monosac = null; try { monosac = new SimpleMonosaccharide( basetype ); if ( substituents != null ) for ( int i = 0; i < substituents.size(); i++ ) if ( substituents.get(i) != null ) monosac.attach( substituents.get(i), i+1 ); } catch ( Exception ex ) { SequenceFormatException sfex = parser.createSyntaxException( this.token, ex.getMessage() ); sfex.initCause( ex ); throw sfex; } if ( anomer != null ) monosac.setAnomer( anomer ); if ( conformation != null ) monosac.setRingConformation( conformation ); this.residue = monosac; return monosac; } public void setAnomer( Anomer a ) { anomer = a; } public void setBasetype( Basetype b ) { basetype = b; } public void setSuperclass( Superclass s ) { superclass = s; } public void setRingConformation( RingConformation rc ) { conformation = rc; if ( residue != null ) ((Monosaccharide) residue).setRingConformation( rc ); } public void setSubstituent( Substituent s, int position ) throws IllegalArgumentException { if ( substituents == null ) { if ( superclass != null ) substituents = Arrays.asList( new Substituent[ superclass.size() ] ); else if ( basetype != null ) substituents = Arrays.asList( new Substituent[ basetype.getSuperclass().size() ] ); else assert false; } if ( position < 1 ) throw new IllegalArgumentException( "position cannot be less than 1"); if ( position > substituents.size() ) throw new IllegalArgumentException( "position cannot be greater than monosaccharide size"); // if ( position == ringStart ) // throw new IllegalArgumentException( // "position cannot be equal to ring start position"); if ( position == ringEnd ) throw new IllegalArgumentException( "position cannot be equal to ring end position"); // substituents[position - 1] = s int i = position - 1; if ( substituents.get( i ) != null ) { if ( s == Deoxy && substituents.get( i ) == En ) return; log.warn( "displacing existing substituent " + s + " at position " + position + " with substituent " + substituents.get( i ) ); } substituents.set( i, s ); } public void setRingStart( int pos ) { ringStart = pos; _check_ring(); } public void setRingEnd( int pos ) { ringEnd = pos; _check_ring(); } private final void _check_ring() { if ( ringStart > 0 && ringEnd > 0 ) { assert ringEnd > ringStart; setRingConformation( RingConformation.forRingPositions( ringStart, ringEnd ) ); } } // /** Returns this token's text. */ // public String toString() // { // return // "<token: text=" // + token.getText() // + ", residue=" // + ( residue != null // ? residue.toString() // : "null" ) // + ">" // // + "], line=" // // // + token.getText() // // + token.getLine() // // + ", col=" // // + token.getColumn() // // + ">" // ; // } } // end class MonosacResidueToken