public static void Parse( IParser p, string text, string seperators, QueryTranslator q )
		{
			StringTokenizer tokens = new StringTokenizer( text, seperators, true );
			p.Start( q );
			foreach( string token in tokens )
			{
				p.Token( token, q );
			}
			p.End( q );
		}
		public string ContinueFromManyToMany( System.Type clazz, string[ ] joinColumns, QueryTranslator q )
		{
			Start( q );
			continuation = true;
			currentName = q.CreateNameFor( clazz );
			q.AddType( currentName, clazz );
			IQueryable classPersister = q.GetPersister( clazz );
			join.AddJoin( classPersister.TableName, currentName, joinColumns, classPersister.IdentifierColumnNames, joinType );
			currentPropertyMapping = classPersister;
			return currentName;
		}
		public void Token( string token, QueryTranslator q )
		{
			if( q.IsName( StringHelper.Root( token ) ) )
			{
				ParserHelper.Parse( pathExpressionParser, q.Unalias( token ), ParserHelper.PathSeparators, q );
				q.AppendGroupByToken( pathExpressionParser.WhereColumn );
				pathExpressionParser.AddAssociation( q );
			}
			else
			{
				q.AppendGroupByToken( token );
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		public override void End( QueryTranslator q )
		{
			if( !IsCollectionValued )
			{
				IType type = PropertyType;
				if( type.IsEntityType )
				{
					// "finish off" the join
					Token( ".", q );
					Token( null, q );
				}
				else if( type.IsPersistentCollectionType )
				{
					// default to element set if no elements() specified
					Token( ".", q );
					Token( CollectionPropertyMapping.CollectionElements, q );
				}
			}
			base.End( q );
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="token"></param>
		/// <param name="q"></param>
		public void Token( string token, QueryTranslator q )
		{
			if( q.IsName( StringHelper.Root( token ) ) )
			{
				ParserHelper.Parse( pathExpressionParser, q.Unalias( token ), ParserHelper.PathSeparators, q );
				q.AppendOrderByToken( pathExpressionParser.WhereColumn );
				pathExpressionParser.AddAssociation( q );
			}
			else if ( token.StartsWith( ParserHelper.HqlVariablePrefix ) )
			{
				q.AddNamedParameter( token.Substring( 1 ) );
				// this is only a temporary parameter to help with the parsing of hql - 
				// when the type becomes known then this will be converted to its real
				// parameter type.
				//AppendToken( q, new SqlString( new object[ ] {new Parameter( StringHelper.SqlParameter )} ) );
			}
			else
			{
				q.AppendOrderByToken( token );
			}
		}
		private void DereferenceCollection(String propertyName, String role, QueryTranslator q)
		{
			collectionRole = role;
			IQueryableCollection collPersister = q.GetCollectionPersister( role );
			string[] colNames = collPersister.KeyColumnNames;
			string name = q.CreateNameForCollection(role);
			AddJoin( collPersister.TableName, name, colNames );

			if ( collPersister.HasWhere ) 
			{
				join.AddCondition( collPersister.GetSQLWhereString( name ) );
			}
			collectionName = name;
			collectionOwnerName = currentName;
			currentName = name;
			currentProperty = propertyName;
			componentPath = null;
			//componentPath = new StringBuilder();
			currentPropertyMapping = new CollectionPropertyMapping( collPersister );
		}
		private void SetType( QueryTranslator q )
		{
			if( currentProperty == null )
			{
				type = PropertyMapping.Type;
			}
			else
			{
				type = PropertyType;
			}
		}
		private void DoPathExpression( string token, QueryTranslator q )
		{
			Preprocess( token, q );

			StringTokenizer tokens = new StringTokenizer( token, ".", true );
			pathExpressionParser.Start( q );
			foreach( string tok in tokens )
			{
				pathExpressionParser.Token( tok, q );
			}
			pathExpressionParser.End( q );

			if( pathExpressionParser.IsCollectionValued )
			{
				OpenExpression( q, string.Empty );
				AppendToken( q, pathExpressionParser.GetCollectionSubquery() );
				CloseExpression( q, string.Empty );
				// this is ugly here, but needed because its a subquery
				q.AddQuerySpace( q.GetCollectionPersister( pathExpressionParser.CollectionRole ).CollectionSpace );
			}
			else
			{
				if( pathExpressionParser.IsExpectingCollectionIndex )
				{
					expectingIndex++;
				}
				else
				{
					AddJoin( pathExpressionParser.WhereJoin, q );
					AppendToken( q, pathExpressionParser.WhereColumn );
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		/// <param name="token"></param>
		protected virtual void AppendToken( QueryTranslator q, SqlString token )
		{
			if( expectingIndex > 0 )
			{
				pathExpressionParser.LastCollectionElementIndexValue = token.ToString();
			}
			else
			{
				q.AppendWhereToken( token );
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		public void AddAssociation( QueryTranslator q )
		{
			q.AddJoin( Name, join );
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		/// <returns></returns>
		public string AddFromCollection( QueryTranslator q )
		{
			IType collectionElementType = PropertyType;

			if( collectionElementType == null )
			{
				throw new QueryException( string.Format( "must specify 'elements' for collection valued property in from clause: {0}", path ) );
			}
			if( collectionElementType.IsEntityType )
			{
				// an association
				IQueryableCollection collectionPersister = q.GetCollectionPersister( collectionRole );
				IQueryable entityPersister = (IQueryable) collectionPersister.ElementPersister;
				System.Type clazz = entityPersister.MappedClass;

				string[] collectionElementColumns = CurrentColumns();

				string elementName;
				if ( collectionPersister.IsOneToMany )
				{
					elementName = collectionName;
					// allow index() function
					q.DecoratePropertyMapping( elementName, collectionPersister );
				}
				else
				{
					// many to many
					q.AddCollection( collectionName, collectionRole );
					elementName = q.CreateNameFor( clazz );
					string[] keyColumnNames = entityPersister.IdentifierColumnNames;
					join.AddJoin( entityPersister.TableName, elementName, collectionElementColumns, keyColumnNames, joinType );
				}
				q.AddFrom( elementName, clazz, join );
				currentPropertyMapping = new CollectionPropertyMapping( collectionPersister );
				return elementName;
			}
			else
			{
				// collection of values
				q.AddFromCollection( collectionName, collectionRole, join );
				return collectionName;
			}
		}
		public virtual void Start( QueryTranslator q )
		{
			entityName = null;
			alias = null;
			afterIn = false;
			afterAs = false;
			afterClass = false;
			expectingJoin = false;
			expectingIn = false;
			expectingAs = false;
			joinType = JoinType.None;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		public virtual void End( QueryTranslator q )
		{
			ignoreInitialJoin = false;

			IType propertyType = PropertyType;
			if( propertyType != null && propertyType.IsPersistentCollectionType )
			{
				collectionRole = ( ( PersistentCollectionType ) propertyType ).Role;
				collectionName = q.CreateNameForCollection( collectionRole );
				PrepareForIndex( q );
			}
			else
			{
				columns = CurrentColumns( );
				SetType( q );
			}

			//important!!
			continuation = false;
		}
		public void End( QueryTranslator q )
		{
		}
		/// <summary>
		/// Compile a subquery
		/// </summary>
		/// <param name="superquery"></param>
		protected internal void Compile( QueryTranslator superquery )
		{
			this.factory = superquery.factory;
			this.tokenReplacements = superquery.tokenReplacements;
			this.superQuery = superquery;
			this.shallowQuery = true;

			Compile( );
		}
		public void Start( QueryTranslator q )
		{
		}
		private void DoToken( string token, QueryTranslator q )
		{
			if( q.IsName( StringHelper.Root( token ) ) ) //path expression
			{
				DoPathExpression( q.Unalias( token ), q );
			}
			else if( token.StartsWith( ParserHelper.HqlVariablePrefix ) ) //named query parameter
			{
				q.AddNamedParameter( token.Substring( 1 ) );
				// this is only a temporary parameter to help with the parsing of hql - 
				// when the type becomes known then this will be converted to its real
				// parameter type.
				AppendToken( q, new SqlString( new object[ ] {new Parameter( StringHelper.SqlParameter )} ) );
			}
			else if( token.Equals( StringHelper.SqlParameter ) )
			{
				//if the token is a "?" then we have a Parameter so convert it to a SqlCommand.Parameter
				// instead of appending a "?" to the WhereTokens
				q.AppendWhereToken( new SqlString( new object[ ] {new Parameter( StringHelper.SqlParameter)} ) );
			}
			else
			{
				IQueryable persister = q.GetPersisterUsingImports( token );
				if( persister != null ) // the name of a class
				{
					object discrim = persister.DiscriminatorSQLValue;
					if ( InFragment.Null == discrim || InFragment.NotNull == discrim )
					{
						throw new QueryException( "subclass test not allowed for null or not null discriminator" );
					}
					AppendToken( q, discrim.ToString() );
				}
				else
				{
					object constant;
					string fieldName = null;
					string typeName = null;
					string importedName = null;

					int indexOfDot = token.IndexOf( StringHelper.Dot );
					// don't even bother to do the lookups if the indexOfDot is not 
					// greater than -1.  This will save all the string modifications.

					// This allows us to resolve to the full type before obtaining the value e.g. FooStatus.OFF -> NHibernate.Model.FooStatus.OFF
					if( indexOfDot > -1 )
					{
						fieldName = StringHelper.Unqualify( token );
						typeName = StringHelper.Qualifier( token );
						importedName = q.factory.GetImportedClassName( typeName );
					}

					if( indexOfDot > - 1 &&
						( constant = ReflectHelper.GetConstantValue( importedName, fieldName ) ) != null )
					{
						// need to get the NHibernate Type so we can convert the Enum or field from 
						// a class into it's string representation for hql.
						IType type;
						try
						{
							type = TypeFactory.HeuristicType( constant.GetType().AssemblyQualifiedName );
						}
						catch( MappingException me )
						{
							throw new QueryException( me );
						}

						if ( type == null )
						{
							throw new QueryException( string.Format( "Could not determin the type of: {0}", token ) );
						}

						try
						{
							AppendToken( q, ( ( ILiteralType ) type ).ObjectToSQLString( constant ) );
						}
						catch( Exception e )
						{
							throw new QueryException( "Could not format constant value to SQL literal: " + token, e );
						}
					}
					else
					{
						//anything else

						string negatedToken = negated ? ( string ) negations[ token.ToLower( System.Globalization.CultureInfo.InvariantCulture ) ] : null;
						if( negatedToken != null && ( !betweenSpecialCase || !"or".Equals( negatedToken ) ) )
						{
							AppendToken( q, negatedToken );
						}
						else
						{
							AppendToken( q, token );
						}
					}
				}
			}
		}
		private bool ContinuePathExpression( string token, QueryTranslator q )
		{
			expectingPathContinuation = false;

			PathExpressionParser.CollectionElement element = pathExpressionParser.LastCollectionElement();

			if( token.StartsWith( "." ) )
			{ // the path expression continues after a ]

				DoPathExpression( GetElementName( element, q ) + token, q ); // careful with this!

				AddToCurrentJoin( element );
				return true; //NOTE: EARLY EXIT!

			}
			else
			{
				// the path expression ends at the ]
				if( element.ElementColumns.Length != 1 )
				{
					throw new QueryException( "path expression ended in composite collection element" );
				}
				AppendToken( q, element.ElementColumns[ 0 ] );
				AddToCurrentJoin( element );
				return false;
			}
		}
		private void Reset( QueryTranslator q )
		{
			join = q.CreateJoinFragment( useThetaStyleJoin );
			dotcount = 0;
			currentName = null;
			currentProperty = null;
			collectionName = null;
			collectionRole = null;
			componentPath = null;
			type = null;
			collectionName = null;
			columns = null;
			expectingCollectionIndex = false;
			continuation = false;
			currentPropertyMapping = null;
		}
		public virtual void End( QueryTranslator q )
		{
			if( alias != null && expectingIn )
			{
				throw new QueryException( "in expected: <end-of-text>"
					+ " (possibly an invalid or unmapped class name was used in the query)");
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		public void Start( QueryTranslator q )
		{
			if( !continuation )
			{
				Reset( q );
				path = null;
			}
		}
		public void Token( string token, QueryTranslator q )
		{
			// start by looking for HQL keywords....
			string lcToken = token.ToLower( System.Globalization.CultureInfo.InvariantCulture );
			if( lcToken.Equals( StringHelper.Comma ) )
			{
				if( !( expectingJoin | expectingAs ) )
				{
					throw new QueryException( "unexpected token: ," );
				}
				expectingJoin = false;
				expectingAs = false;
			}
			else if( lcToken.Equals( "join" ) )
			{
				if( !afterJoinType )
				{
					if( !( expectingJoin | expectingAs ) )
					{
						throw new QueryException( "unexpected token: join" );
					}
					// inner joins can be abbreviated to 'join'
					joinType = JoinType.InnerJoin;
					expectingJoin = false;
					expectingAs = false;
				}
				else
				{
					afterJoinType = false;
				}
			}
			else if( lcToken.Equals( "fetch" ) )
			{
				if( q.IsShallowQuery )
				{
					throw new QueryException( "fetch may not be used with scroll() or iterate()" );
				}
				if( joinType == JoinType.None )
				{
					throw new QueryException( "unexpected token: fetch" );
				}
				if( joinType == JoinType.FullJoin || joinType == JoinType.RightOuterJoin )
				{
					throw new QueryException( "fetch may only be used with inner join or left outer join" );
				}
				afterFetch = true;
			}
			else if( lcToken.Equals( "outer" ) )
			{
				// 'outer' is optional and is ignored)
				if( !afterJoinType || ( joinType != JoinType.LeftOuterJoin && joinType != JoinType.RightOuterJoin ) )
				{
					throw new QueryException( "unexpected token: outer" );
				}
			}
			else if( joinTypes.Contains( lcToken ) )
			{
				if( !( expectingJoin | expectingAs ) )
				{
					throw new QueryException( "unexpected token: " + token );
				}
				joinType = ( JoinType ) joinTypes[ lcToken ];
				afterJoinType = true;
				expectingJoin = false;
				expectingAs = false;
			}
			else if( lcToken.Equals( "class" ) )
			{
				if( !afterIn )
				{
					throw new QueryException( "unexpected token: class" );
				}
				if( joinType != JoinType.None )
				{
					throw new QueryException( "outer or full join must be followed by path expression" );
				}
				afterClass = true;
			}
			else if( lcToken.Equals( "in" ) )
			{
				if( !expectingIn )
				{
					throw new QueryException( "unexpected token: in" );
				}
				afterIn = true;
				expectingIn = false;
			}
			else if( lcToken.Equals( "as" ) )
			{
				if( !expectingAs )
				{
					throw new QueryException( "unexpected token: as" );
				}
				afterAs = true;
				expectingAs = false;
			}
			else
			{
				if( afterJoinType )
				{
					throw new QueryException( "join expected: " + token );
				}
				if( expectingJoin )
				{
					throw new QueryException( "unexpected token: " + token );
				}
				if( expectingIn )
				{
					throw new QueryException( "in expected: " + token );
				}

				// now anything that is not a HQL keyword

				if( afterAs || expectingAs )
				{
					// (AS is always optional, for consistentcy with SQL/OQL

					// process the "new" HQL stype where aliases are assigned
					// _after_ the class name or path expression ie using the
					// AS construction

					if( entityName != null )
					{
						q.SetAliasName( token, entityName );
					}
					else
					{
						throw new QueryException( "unexpected: as " + token );
					}
					afterAs = false;
					expectingJoin = true;
					expectingAs = false;
					entityName = null;
				}
				else if( afterIn )
				{
					// process the "old" HQL style where aliases appear _first
					// ie using the IN or IN CLASS constructions

					if( alias == null )
					{
						throw new QueryException( "alias not specified for: " + token );
					}

					if( joinType != JoinType.None )
					{
						throw new QueryException( "outer or full join must be followed by path expressions" );
					}

					if( afterClass )
					{
						// treat it as a classname
						IQueryable p = q.GetPersisterUsingImports( token );
						if( p == null )
						{
							throw new QueryException( "persister not found: " + token );
						}
						q.AddFromClass( alias, p );
					}
					else
					{
						// treat it as a path expression
						peParser.JoinType = JoinType.InnerJoin;
						peParser.UseThetaStyleJoin = true;
						ParserHelper.Parse( peParser, q.Unalias( token ), ParserHelper.PathSeparators, q );
						if( !peParser.IsCollectionValued )
						{
							throw new QueryException( "pathe expression did not resolve to collection: " + token );
						}
						string nm = peParser.AddFromCollection( q );
						q.SetAliasName( alias, nm );
					}

					alias = null;
					afterIn = false;
					afterClass = false;
					expectingJoin = true;
				}
				else
				{
					// handle a path expression or class name that appears
					// at the start, in the "new" HQL style or an alias that
					// appears at the start in the "old HQL stype
					IQueryable p = q.GetPersisterUsingImports( token );
					if( p != null )
					{
						// starts with the name of a mapped class (new style)
						if( joinType != JoinType.None )
						{
							throw new QueryException( "outer or full join must be followed by path expression" );
						}
						entityName = q.CreateNameFor( p.MappedClass );
						q.AddFromClass( entityName, p );
						expectingAs = true;
					}
					else if( token.IndexOf( '.' ) < 0 )
					{
						// starts with an alias (old style)
						// semi-bad thing about this: can't re-alias another alias...
						alias = token;
						expectingIn = true;
					}
					else
					{
						// starts with a path expression (new style)

						// force HQL style: from Person p inner join p.cars c
						//if (joinType==JoinType.None) throw new QueryException("path expression must be preceded by full, left, right or inner join");

						//allow ODMG OQL style: from Person p, p.cars c
						if( joinType != JoinType.None )
						{
							peParser.JoinType = joinType;
						}
						else
						{
							peParser.JoinType = JoinType.InnerJoin;
						}
						peParser.UseThetaStyleJoin = q.IsSubquery;

						ParserHelper.Parse( peParser, q.Unalias( token ), ParserHelper.PathSeparators, q );
						entityName = peParser.AddFromAssociation( q );

						joinType = JoinType.None;
						peParser.JoinType = JoinType.InnerJoin;

						if( afterFetch )
						{
							peParser.Fetch( q, entityName );
							afterFetch = false;
						}

						expectingAs = true;
					}
				}
			}
		}
		private void PrepareForIndex( QueryTranslator q )
		{
			IQueryableCollection collPersister = q.GetCollectionPersister( collectionRole );

			if( !collPersister.HasIndex )
			{
				throw new QueryException( "unindexed collection before []" );
			}
			string[ ] indexCols = collPersister.IndexColumnNames;
			if( indexCols.Length != 1 )
			{
				throw new QueryException( "composite-index appears in []: " + path );
			}
			string[ ] keyCols = collPersister.KeyColumnNames;

			JoinFragment ojf = q.CreateJoinFragment( useThetaStyleJoin );
			ojf.AddCrossJoin( collPersister.TableName, collectionName );
			ojf.AddFromFragmentString( join.ToFromFragmentString );
			if( collPersister.IsOneToMany )
			{
				IQueryable persister = (IQueryable) collPersister.ElementPersister;
				ojf.AddJoins(
					( (IJoinable) persister).FromJoinFragment( collectionName, true, false ),
					( (IJoinable) persister).WhereJoinFragment( collectionName, true, false )
					);
			}

			if( !continuation )
			{
				AddJoin( collPersister.TableName, collectionName, keyCols );
			}
			join.AddCondition( collectionName, indexCols, " = " );

			string[ ] eltCols = collPersister.ElementColumnNames;

			CollectionElement elem = new CollectionElement();
			elem.ElementColumns = StringHelper.Qualify( collectionName, eltCols );
			elem.Type = collPersister.ElementType;
			elem.IsOneToMany = collPersister.IsOneToMany;
			elem.Alias = collectionName;
			elem.Join = join;
			collectionElements.Add( elem ); //addlast
			SetExpectingCollectionIndex();

			q.AddCollection( collectionName, collectionRole );
			q.AddJoin( collectionName, ojf );
		}
		private void Preprocess( string token, QueryTranslator q )
		{
			// ugly hack for cases like "foo.bar.collection.elements" 
			// (multi-part path expression ending in elements or indices) 
			string[ ] tokens = StringHelper.Split( ".", token, true );
			if( tokens.Length > 5 &&
				( "elements".Equals( tokens[ tokens.Length - 1 ] ) || "indices".Equals( tokens[ tokens.Length - 1 ] ) ) )
			{
				pathExpressionParser.Start( q );
				for( int i = 0; i < tokens.Length - 3; i++ )
				{
					pathExpressionParser.Token( tokens[ i ], q );
				}
				pathExpressionParser.Token( null, q );
				pathExpressionParser.End( q );
				AddJoin( pathExpressionParser.WhereJoin, q );
				pathExpressionParser.IgnoreInitialJoin();
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		/// <returns></returns>
		public string AddFromAssociation( QueryTranslator q )
		{
			if ( IsCollectionValued )
			{
				return AddFromCollection( q );
			}
			else
			{
				q.AddFrom( currentName, join );
				return currentName;
			}
		}
		private void AddJoin( JoinFragment ojf, QueryTranslator q )
		{
			JoinFragment fromClause = q.CreateJoinFragment( true );
			fromClause.AddJoins( ojf.ToFromFragmentString, new SqlString( String.Empty ) );
			q.AddJoin( pathExpressionParser.Name, fromClause );
			//TODO: HACK with ToString()
			AddToCurrentJoin( ojf.ToWhereFragmentString.ToString() );
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		/// <param name="entityName"></param>
		public void Fetch( QueryTranslator q, string entityName )
		{
			if ( IsCollectionValued )
			{
				q.SetCollectionToFetch( CollectionRole, CollectionName, CollectionOwnerName, entityName );
			}
			else
			{
				q.AddEntityToFetch( entityName, oneToOneOwnerName );
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="propertyName"></param>
		/// <param name="propertyType"></param>
		/// <param name="q"></param>
		/// <remarks>NOTE: we avoid joining to the next table if the named property is just the foreign key value</remarks>
		private void DereferenceEntity( string propertyName, EntityType propertyType, QueryTranslator q )
		{
			//if its "id"
			bool isIdShortcut = EntityID.Equals(propertyName) && !propertyType.IsUniqueKeyReference;
			
			//or its the id property name
			string idPropertyName;
			try 
			{
				idPropertyName = propertyType.GetIdentifierOrUniqueKeyPropertyName( q.Factory );
			}
			catch (MappingException me) 
			{
				throw new QueryException(me);
			}
			bool isNamedIdPropertyShortcut = idPropertyName != null && 	idPropertyName.Equals( propertyName );
			
			if ( isIdShortcut || isNamedIdPropertyShortcut ) 
			{
				// special shortcut for id properties, skip the join!
				// this must only occur at the _end_ of a path expression
				DereferenceProperty( propertyName );
			}
			else 
			{
				System.Type entityClass = propertyType.AssociatedClass;
				String name = q.CreateNameFor( entityClass );
				q.AddType( name, entityClass );
				IQueryable memberPersister = q.GetPersister( entityClass );
				//String[] keyColNames = memberPersister.getIdentifierColumnNames();
				string[] keyColNames;
				try 
				{
					keyColNames = propertyType.GetReferencedColumns( q.Factory );
				}
				catch (MappingException me) 
				{
					throw new QueryException(me);
				}
				AddJoin( memberPersister.TableName, name, keyColNames );
				if ( propertyType.IsOneToOne ) 
				{
					oneToOneOwnerName = currentName;
				}
				currentName = name;
				currentProperty = propertyName;
				q.AddPathAliasAndJoin( path.Substring( 0, path.LastIndexOf( StringHelper.Dot ) ), name, join );
				componentPath = null;
				//componentPath = new StringBuilder( );
				currentPropertyMapping = memberPersister;
			}
		}
		public void Token( string token, QueryTranslator q )
		{
			if( token != null )
			{
				path += token;
			}

			string alias = q.GetPathAlias( path );
			if( alias != null )
			{
				Reset( q ); //reset the dotcount (but not the path)
				currentName = alias; //after reset!
				currentPropertyMapping = q.GetPropertyMapping( currentName );
				if( !ignoreInitialJoin )
				{
					JoinFragment ojf = q.GetPathJoin( path );
					join.AddCondition( ojf.ToWhereFragmentString ); //after reset!
					// we don't need to worry about any condition in the ON clause
					// here (toFromFragmentString), since anything in the ON condition 
					// is already applied to the whole query
				}
			}
			else if( ".".Equals( token ) )
			{
				dotcount++;
			}
			else
			{
				if( dotcount == 0 )
				{
					if( !continuation )
					{
						if( !q.IsName( token ) )
						{
							throw new QueryException( "undefined alias or unknown mapping: " + token );
						}
						currentName = token;
						currentPropertyMapping = q.GetPropertyMapping( currentName );
					}
				}
				else if( dotcount == 1 )
				{
					if( currentName != null )
					{
						currentProperty = token;
					}
					else if( collectionName != null )
					{
						//IQueryableCollection p = q.GetCollectionPersister( collectionRole );
						//DoCollectionProperty( token, p, collectionName );
						continuation = false;
					}
					else
					{
						throw new QueryException( "unexpected" );
					}
				}
				else
				{ // dotcount>=2

					// Do the corresponding RHS
					IType propertyType = PropertyType;

					if( propertyType == null )
					{
						throw new QueryException( "unresolved property: " + currentProperty );
					}

					if( propertyType.IsComponentType )
					{
						DereferenceComponent( token );
					}
					else if( propertyType.IsEntityType )
					{
						DereferenceEntity( token, (EntityType) propertyType, q );
					}
					else if( propertyType.IsPersistentCollectionType )
					{
						DereferenceCollection( token, ( (PersistentCollectionType) propertyType).Role, q );
					}
					else if( token != null )
					{
						throw new QueryException( "dereferenced: " + currentProperty );
					}
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="q"></param>
		/// <param name="token"></param>
		protected virtual void AppendToken( QueryTranslator q, string token )
		{
			if( expectingIndex > 0 )
			{
				pathExpressionParser.LastCollectionElementIndexValue = token;
			}
			else
			{
				// a String.Empty can get passed in here.  If that occurs
				// then don't create a new SqlString for it - just ignore
				// it since it adds nothing to the sql being generated.
				if( token != null && token.Length > 0 )
				{
					q.AppendWhereToken( new SqlString( token ) );
				}
			}
		}